homebridge-tasmota-control 1.4.0-beta.3 → 1.4.0-beta.31

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 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 Fan, solved [#24](https://github.com/grzegorz914/homebridge-tasmota-control/issues/24)
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 TasmotaDevice from './src/tasmotadevice.js';
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 device of config.devices) {
30
+ for (const deviceConfig of config.devices) {
27
31
 
28
32
  //check accessory is enabled
29
- const disableAccessory = device.disableAccessory || false;
33
+ const disableAccessory = deviceConfig.disableAccessory || false;
30
34
  if (disableAccessory) {
31
35
  continue;
32
36
  }
33
37
 
34
- const deviceName = device.name;
35
- const host = device.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 enableDebugMode = device.enableDebugMode || false;
43
- const disableLogDeviceInfo = device.disableLogDeviceInfo || false;
44
- const disableLogInfo = device.disableLogInfo || false;
45
- const disableLogSuccess = device.disableLogSuccess || false;
46
- const disableLogWarn = device.disableLogWarn || false;
47
- const disableLogError = device.disableLogError || false;
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 config = {
50
- ...device,
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(config, null, 2)}.`);
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 = device.host.split('.').join('');
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
- const miElHvac = device.miElHvac ?? {};
81
- const tasmotaDevice = new TasmotaDevice(api, device, miElHvac, defaultHeatingSetTemperatureFile, defaultCoolingSetTemperatureFile);
82
- tasmotaDevice.on('publishAccessory', (accessory) => {
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 deviceInfo.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 tasmotaDevice.start();
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 tasmotaDevice.startImpulseGenerator() : false
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
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "displayName": "Tasmota Control",
3
3
  "name": "homebridge-tasmota-control",
4
- "version": "1.4.0-beta.3",
4
+ "version": "1.4.0-beta.31",
5
5
  "description": "Homebridge plugin to control Tasmota flashed devices.",
6
6
  "license": "MIT",
7
7
  "author": "grzegorz914",
@@ -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;