homebridge-tasmota-control 1.4.0-beta.3 → 1.4.0-beta.30
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/CHANGELOG.md +1 -1
- package/index.js +62 -22
- package/package.json +1 -1
- package/src/deviceinfo.js +77 -0
- package/src/fans.js +713 -0
- package/src/lights.js +734 -0
- package/src/mielhvac.js +1398 -0
- package/src/switches.js +623 -0
- package/src/tasmotadevice.js +0 -2532
package/CHANGELOG.md
CHANGED
|
@@ -9,7 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
9
9
|
|
|
10
10
|
## Changes
|
|
11
11
|
|
|
12
|
-
- added support for
|
|
12
|
+
- added support for iFan, solved [#24](https://github.com/grzegorz914/homebridge-tasmota-control/issues/24)
|
|
13
13
|
- config schema updated
|
|
14
14
|
- redme updated
|
|
15
15
|
- cleanup
|
package/index.js
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
import { join } from 'path';
|
|
2
2
|
import { mkdirSync, existsSync, writeFileSync } from 'fs';
|
|
3
|
-
import
|
|
3
|
+
import deviceinfo from './src/deviceinfo.js';
|
|
4
|
+
import mielhvac from './src/mielhvac.js';
|
|
5
|
+
import switches from './src/switches.js';
|
|
6
|
+
import lights from './src/lights.js';
|
|
7
|
+
import fans from './src/fans.js';
|
|
4
8
|
import ImpulseGenerator from './src/impulsegenerator.js';
|
|
5
|
-
import { PluginName, PlatformName } from './src/constants.js';
|
|
9
|
+
import { PluginName, PlatformName, ApiCommands, LightKeys } from './src/constants.js';
|
|
6
10
|
|
|
7
11
|
class tasmotaPlatform {
|
|
8
12
|
constructor(log, config, api) {
|
|
@@ -23,38 +27,44 @@ class tasmotaPlatform {
|
|
|
23
27
|
}
|
|
24
28
|
|
|
25
29
|
api.on('didFinishLaunching', async () => {
|
|
26
|
-
for (const
|
|
30
|
+
for (const deviceConfig of config.devices) {
|
|
27
31
|
|
|
28
32
|
//check accessory is enabled
|
|
29
|
-
const disableAccessory =
|
|
33
|
+
const disableAccessory = deviceConfig.disableAccessory || false;
|
|
30
34
|
if (disableAccessory) {
|
|
31
35
|
continue;
|
|
32
36
|
}
|
|
33
37
|
|
|
34
|
-
const deviceName =
|
|
35
|
-
const host =
|
|
38
|
+
const deviceName = deviceConfig.name;
|
|
39
|
+
const host = deviceConfig.host;
|
|
36
40
|
if (!deviceName || !host) {
|
|
37
41
|
log.warn(`Device Name: ${deviceName ? 'OK' : deviceName}, host: ${host ? 'OK' : host}, in config wrong or missing.`);
|
|
38
42
|
return;
|
|
39
43
|
}
|
|
40
44
|
|
|
41
45
|
//log config
|
|
42
|
-
const
|
|
43
|
-
const
|
|
44
|
-
const
|
|
45
|
-
const
|
|
46
|
-
const
|
|
47
|
-
const
|
|
46
|
+
const loadNameFromDevice = deviceConfig.loadNameFromDevice || false;
|
|
47
|
+
const auth = deviceConfig.auth || false;
|
|
48
|
+
const url = `http://${host}/cm?cmnd=`;
|
|
49
|
+
const user = deviceConfig.user || '';
|
|
50
|
+
const passwd = deviceConfig.passwd || '';
|
|
51
|
+
const refreshInterval = deviceConfig.refreshInterval * 1000 || 5000;
|
|
52
|
+
const enableDebugMode = deviceConfig.enableDebugMode || false;
|
|
53
|
+
const disableLogDeviceInfo = deviceConfig.disableLogDeviceInfo || false;
|
|
54
|
+
const disableLogInfo = deviceConfig.disableLogInfo || false;
|
|
55
|
+
const disableLogSuccess = deviceConfig.disableLogSuccess || false;
|
|
56
|
+
const disableLogWarn = deviceConfig.disableLogWarn || false;
|
|
57
|
+
const disableLogError = deviceConfig.disableLogError || false;
|
|
48
58
|
const debug = enableDebugMode ? log.info(`Device: ${host} ${deviceName}, debug: Did finish launching.`) : false;
|
|
49
|
-
const
|
|
50
|
-
...
|
|
59
|
+
const newConfig = {
|
|
60
|
+
...deviceConfig,
|
|
51
61
|
user: 'removed',
|
|
52
62
|
passwd: 'removed'
|
|
53
63
|
};
|
|
54
|
-
const debug1 = !enableDebugMode ? false : log.info(`Device: ${host} ${deviceName}, Config: ${JSON.stringify(
|
|
64
|
+
const debug1 = !enableDebugMode ? false : log.info(`Device: ${host} ${deviceName}, Config: ${JSON.stringify(newConfig, null, 2)}.`);
|
|
55
65
|
|
|
56
66
|
//check files exists, if not then create it
|
|
57
|
-
const postFix =
|
|
67
|
+
const postFix = deviceConfig.host.split('.').join('');
|
|
58
68
|
const defaultHeatingSetTemperatureFile = `${prefDir}/defaultHeatingSetTemperature_${postFix}`;
|
|
59
69
|
const defaultCoolingSetTemperatureFile = `${prefDir}/defaultCoolingSetTemperature_${postFix}`;
|
|
60
70
|
|
|
@@ -75,11 +85,41 @@ class tasmotaPlatform {
|
|
|
75
85
|
return;
|
|
76
86
|
}
|
|
77
87
|
|
|
78
|
-
//tasmota device
|
|
79
88
|
try {
|
|
80
|
-
|
|
81
|
-
const
|
|
82
|
-
|
|
89
|
+
//get device info
|
|
90
|
+
const deviceInfo = new deviceinfo(url, auth, user, passwd, deviceName, loadNameFromDevice, enableDebugMode, refreshInterval);
|
|
91
|
+
deviceInfo.on('debug', (debug) => {
|
|
92
|
+
const emitLog = !enableDebugMode ? false : log.info(`Device: ${host} ${deviceName}, debug: ${debug}.`);
|
|
93
|
+
})
|
|
94
|
+
.on('warn', (warn) => {
|
|
95
|
+
const emitLog = disableLogWarn ? false : log.warn(`Device: ${host} ${deviceName}, ${warn}.`);
|
|
96
|
+
})
|
|
97
|
+
.on('error', (error) => {
|
|
98
|
+
const emitLog = disableLogError ? false : log.error(`Device: ${host} ${deviceName}, ${error}.`);
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
const info = await info.getInfo();
|
|
102
|
+
if (!info.serialNumber) {
|
|
103
|
+
this.emit('warn', `Serial number not found`);
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
let device;
|
|
108
|
+
switch (info.deviceType) {
|
|
109
|
+
case 0://mielhvac
|
|
110
|
+
device = new mielhvac(api, deviceConfig, info, refreshInterval, defaultHeatingSetTemperatureFile, defaultCoolingSetTemperatureFile);
|
|
111
|
+
case 1://switches
|
|
112
|
+
device = new switches(api, deviceConfig, info, refreshInterval);
|
|
113
|
+
break;
|
|
114
|
+
case 2://lights
|
|
115
|
+
device = new lights(api, deviceConfig, info, refreshInterval);
|
|
116
|
+
break;
|
|
117
|
+
case 3://fans
|
|
118
|
+
device = new fans(api, deviceConfig, info, refreshInterval);
|
|
119
|
+
break;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
device.on('publishAccessory', (accessory) => {
|
|
83
123
|
api.publishExternalAccessories(PluginName, [accessory]);
|
|
84
124
|
const emitLog = disableLogSuccess ? false : log.success(`Device: ${host} ${deviceName}, Published as external accessory.`);
|
|
85
125
|
})
|
|
@@ -106,11 +146,11 @@ class tasmotaPlatform {
|
|
|
106
146
|
const impulseGenerator = new ImpulseGenerator();
|
|
107
147
|
impulseGenerator.on('start', async () => {
|
|
108
148
|
try {
|
|
109
|
-
const startDone = await
|
|
149
|
+
const startDone = await device.start();
|
|
110
150
|
const stopImpulseGenerator = startDone ? await impulseGenerator.stop() : false;
|
|
111
151
|
|
|
112
152
|
//start impulse generator
|
|
113
|
-
const startImpulseGenerator = stopImpulseGenerator ? await
|
|
153
|
+
const startImpulseGenerator = stopImpulseGenerator ? await device.startImpulseGenerator() : false
|
|
114
154
|
} catch (error) {
|
|
115
155
|
const emitLog = disableLogError ? false : log.error(`Device: ${host} ${deviceName}, ${error}, trying again.`);
|
|
116
156
|
}
|
package/package.json
CHANGED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import axios from 'axios';
|
|
2
|
+
import EventEmitter from 'events';
|
|
3
|
+
import { ApiCommands, LightKeys } from './constants.js';
|
|
4
|
+
|
|
5
|
+
class DeviceInfo extends EventEmitter {
|
|
6
|
+
constructor(url, auth, user, passwd, deviceName, loadNameFromDevice, enableDebugMode, refreshInterval) {
|
|
7
|
+
super();
|
|
8
|
+
this.name = deviceName
|
|
9
|
+
this.loadNameFromDevice = loadNameFromDevice;
|
|
10
|
+
this.enableDebugMode = enableDebugMode;
|
|
11
|
+
|
|
12
|
+
//axios instance
|
|
13
|
+
this.axiosInstance = axios.create({
|
|
14
|
+
method: 'GET',
|
|
15
|
+
baseURL: url,
|
|
16
|
+
timeout: refreshInterval > 10000 ? 10000 : refreshInterval,
|
|
17
|
+
withCredentials: auth,
|
|
18
|
+
auth: {
|
|
19
|
+
username: user,
|
|
20
|
+
password: passwd
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
async getInfo() {
|
|
27
|
+
const debug = this.enableDebugMode ? this.emit('debug', `Requesting info`) : false;
|
|
28
|
+
try {
|
|
29
|
+
const deviceInfoData = await this.axiosInstance(ApiCommands.Status);
|
|
30
|
+
const deviceInfo = deviceInfoData.data ?? {};
|
|
31
|
+
const debug = this.enableDebugMode ? this.emit('debug', `Info: ${JSON.stringify(deviceInfo, null, 2)}`) : false;
|
|
32
|
+
await new Promise(resolve => setTimeout(resolve, 250));
|
|
33
|
+
|
|
34
|
+
//status
|
|
35
|
+
const friendlyNames = [];
|
|
36
|
+
const status = deviceInfo.Status ?? {};
|
|
37
|
+
const deviceName = this.loadNameFromDevice ? status.DeviceName ?? 'Unknown' : this.name;
|
|
38
|
+
const friendlyName = status.FriendlyName ?? [];
|
|
39
|
+
const relaysName = Array.isArray(friendlyName) ? friendlyName : [friendlyName];
|
|
40
|
+
for (const relayName of relaysName) {
|
|
41
|
+
const name = relayName ?? 'Unknown'
|
|
42
|
+
friendlyNames.push(name);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
//status FWR
|
|
46
|
+
const statusFwr = deviceInfo.StatusFWR ?? {};
|
|
47
|
+
const firmwareRevision = statusFwr.Version ?? 'Unknown';
|
|
48
|
+
const modelName = statusFwr.Hardware ?? 'Unknown';
|
|
49
|
+
|
|
50
|
+
//status NET
|
|
51
|
+
const statusNet = deviceInfo.StatusNET ?? {};
|
|
52
|
+
const addressMac = statusNet.Mac ?? false;
|
|
53
|
+
|
|
54
|
+
//status SNS
|
|
55
|
+
const statusSns = deviceInfo.StatusSNS ?? {};
|
|
56
|
+
const statusSnsKeys = Object.keys(statusSns);
|
|
57
|
+
|
|
58
|
+
//status STS
|
|
59
|
+
const statusSts = deviceInfo.StatusSTS ?? {};
|
|
60
|
+
const statusStsKeys = Object.keys(statusSts);
|
|
61
|
+
const deviceType = statusSnsKeys.includes('MiElHVAC') ? 0 : statusStsKeys.some(key => LightKeys.includes(key)) ? 2 : statusStsKeys.includes('FanSpeed') ? 3 : 1;
|
|
62
|
+
const obj = {
|
|
63
|
+
deviceType: deviceType,
|
|
64
|
+
deviceName: deviceName,
|
|
65
|
+
friendlyNames: friendlyNames,
|
|
66
|
+
modelName: modelName,
|
|
67
|
+
serialNumber: addressMac,
|
|
68
|
+
firmwareRevision: firmwareRevision,
|
|
69
|
+
relaysCount: friendlyNames.length
|
|
70
|
+
}
|
|
71
|
+
return obj;
|
|
72
|
+
} catch (error) {
|
|
73
|
+
throw new Error(`Check info error: ${error}`);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
export default DeviceInfo;
|