homebridge-melcloud-control 4.3.2-beta.8 → 4.3.2-beta.9

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "displayName": "MELCloud Control",
3
3
  "name": "homebridge-melcloud-control",
4
- "version": "4.3.2-beta.8",
4
+ "version": "4.3.2-beta.9",
5
5
  "description": "Homebridge plugin to control Mitsubishi Air Conditioner, Heat Pump and Energy Recovery Ventilation.",
6
6
  "license": "MIT",
7
7
  "author": "grzegorz914",
package/src/functions.js CHANGED
@@ -160,5 +160,13 @@ class Functions extends EventEmitter {
160
160
  return v !== undefined && v !== null && !(typeof v === 'number' && Number.isNaN(v));
161
161
  }
162
162
 
163
+ convertValue(value, name) {
164
+ let parsedValue = value;
165
+ if (value === "True") parsedValue = true;
166
+ else if (value === "False") parsedValue = false;
167
+ else if (!isNaN(value) && value !== "") parsedValue = Number(value);
168
+ return [name, parsedValue];
169
+ }
170
+
163
171
  }
164
172
  export default Functions
@@ -70,17 +70,8 @@ class MelCloudAta extends EventEmitter {
70
70
  this.socketConnected = false;
71
71
  }
72
72
 
73
- async checkState() {
73
+ async updateState(deviceData) {
74
74
  try {
75
-
76
- //read device info from file
77
- const devicesData = await this.functions.readData(this.devicesFile, true);
78
- if (!devicesData) return;
79
-
80
- this.headers = devicesData.Headers;
81
- const deviceData = devicesData.Devices.find(device => device.DeviceID === this.deviceId);
82
- deviceData.Scenes = devicesData.Scenes ?? [];
83
-
84
75
  if (this.accountType === 'melcloudhome') {
85
76
  deviceData.Device.OperationMode = AirConditioner.OperationModeMapStringToEnum[deviceData.Device.OperationMode] ?? deviceData.Device.OperationMode;
86
77
  deviceData.Device.ActualFanSpeed = AirConditioner.FanSpeedMapStringToEnum[deviceData.Device.ActualFanSpeed] ?? deviceData.Device.ActualFanSpeed;
@@ -93,87 +84,6 @@ class MelCloudAta extends EventEmitter {
93
84
  deviceData.Device.DefaultHeatingSetTemperature = temps?.defaultHeatingSetTemperature ?? 20;
94
85
  deviceData.Device.DefaultCoolingSetTemperature = temps?.defaultCoolingSetTemperature ?? 24;
95
86
 
96
- //web cocket connection
97
- if (!this.connecting && !this.socketConnected) {
98
- this.connecting = true;
99
-
100
- const url = `${ApiUrlsHome.WebSocketURL}${devicesData.WebSocketOptions.Hash}`;
101
- try {
102
- const socket = new WebSocket(url, { headers: devicesData.WebSocketOptions.Headers })
103
- .on('error', (error) => {
104
- if (this.logError) this.emit('error', `Socket error: ${error}`);
105
- socket.close();
106
- })
107
- .on('close', () => {
108
- if (this.logDebug) this.emit('debug', `Socket closed`);
109
- this.cleanupSocket();
110
- })
111
- .on('open', () => {
112
- this.socket = socket;
113
- this.socketConnected = true;
114
- this.connecting = false;
115
- if (this.logSuccess) this.emit('success', `Socket Connect Success`);
116
-
117
- // heartbeat
118
- this.heartbeat = setInterval(() => {
119
- if (socket.readyState === socket.OPEN) {
120
- if (this.logDebug) this.emit('debug', `Socket send heartbeat`);
121
- socket.ping();
122
- }
123
- }, 30000);
124
- })
125
- .on('pong', () => {
126
- if (this.logDebug) this.emit('debug', `Socket received heartbeat`);
127
- })
128
- .on('message', (message) => {
129
- const parsedMessage = JSON.parse(message);
130
- const stringifyMessage = JSON.stringify(parsedMessage, null, 2);
131
- if (this.logDebug) this.emit('debug', `Incoming message: ${stringifyMessage}`);
132
- if (parsedMessage.message === 'Forbidden') return;
133
-
134
- const messageData = parsedMessage?.[0]?.Data;
135
- if (!messageData) return;
136
-
137
- let updateDeviceState = false;
138
- const unitId = messageData?.id;
139
- switch (unitId) {
140
- case this.deviceId:
141
- const messageType = parsedMessage[0].messageType;
142
- switch (messageType) {
143
- case 'unitStateChanged':
144
- const settings = Object.fromEntries(
145
- messageData.settings.map(({ name, value }) => {
146
- let parsedValue = value;
147
- if (value === "True") parsedValue = true;
148
- else if (value === "False") parsedValue = false;
149
- else if (!isNaN(value) && value !== "") parsedValue = Number(value);
150
- return [name, parsedValue];
151
- })
152
- );
153
- Object.assign(deviceData.Device, settings);
154
- updateDeviceState = true;
155
- break;
156
- case 'unitWifiSignalChanged':
157
- deviceData.Rssi = messageData.rssi;
158
- updateDeviceState = true;
159
- break;
160
- default:
161
- if (!this.logDebug) this.emit('debug', `Unit ${unitId}, received unknown message type: ${stringifyMessage}`);
162
- return;
163
- }
164
- break;
165
- default:
166
- if (!this.logDebug) this.emit('debug', `Incoming unknown unit id: ${stringifyMessage}`);
167
- return;
168
- }
169
-
170
- if (updateDeviceState) this.emit('deviceState', deviceData);
171
- });
172
- } catch (error) {
173
- if (this.logError) this.emit('error', `Socket connection failed: ${error}`);
174
- this.cleanupSocket();
175
- }
176
- }
177
87
  }
178
88
  if (this.logDebug) this.emit('debug', `Device Data: ${JSON.stringify(deviceData, null, 2)}`);
179
89
 
@@ -233,6 +143,104 @@ class MelCloudAta extends EventEmitter {
233
143
  };
234
144
  };
235
145
 
146
+ async checkState() {
147
+ try {
148
+
149
+ //read device info from file
150
+ const devicesData = await this.functions.readData(this.devicesFile, true);
151
+ if (!devicesData) return;
152
+
153
+ this.headers = devicesData.Headers;
154
+ const deviceData = devicesData.Devices.find(device => device.DeviceID === this.deviceId);
155
+ deviceData.Scenes = devicesData.Scenes ?? [];
156
+
157
+ //web cocket connection
158
+ if (this.accountType === 'melcloudhome' && !this.connecting && !this.socketConnected) {
159
+ this.connecting = true;
160
+
161
+ const url = `${ApiUrlsHome.WebSocketURL}${devicesData.WebSocketOptions.Hash}`;
162
+ try {
163
+ const socket = new WebSocket(url, { headers: devicesData.WebSocketOptions.Headers })
164
+ .on('error', (error) => {
165
+ if (this.logError) this.emit('error', `Socket error: ${error}`);
166
+ socket.close();
167
+ })
168
+ .on('close', () => {
169
+ if (this.logDebug) this.emit('debug', `Socket closed`);
170
+ this.cleanupSocket();
171
+ })
172
+ .on('open', () => {
173
+ this.socket = socket;
174
+ this.socketConnected = true;
175
+ this.connecting = false;
176
+ if (this.logSuccess) this.emit('success', `Socket Connect Success`);
177
+
178
+ // heartbeat
179
+ this.heartbeat = setInterval(() => {
180
+ if (socket.readyState === socket.OPEN) {
181
+ if (this.logDebug) this.emit('debug', `Socket send heartbeat`);
182
+ socket.ping();
183
+ }
184
+ }, 30000);
185
+ })
186
+ .on('pong', () => {
187
+ if (this.logDebug) this.emit('debug', `Socket received heartbeat`);
188
+ })
189
+ .on('message', async (message) => {
190
+ const parsedMessage = JSON.parse(message);
191
+ const stringifyMessage = JSON.stringify(parsedMessage, null, 2);
192
+ if (this.logDebug) this.emit('debug', `Incoming message: ${stringifyMessage}`);
193
+ if (parsedMessage.message === 'Forbidden') return;
194
+
195
+ const messageData = parsedMessage?.[0]?.Data;
196
+ if (!messageData) return;
197
+
198
+ let updateDeviceState = false;
199
+ const unitId = messageData?.id;
200
+ switch (unitId) {
201
+ case this.deviceId:
202
+ const messageType = parsedMessage[0].messageType;
203
+ switch (messageType) {
204
+ case 'unitStateChanged':
205
+ const settings = Object.fromEntries(
206
+ messageData.settings.map(({ name, value }) => {
207
+ let parsedValue = this.functions.convertValue(value, name);
208
+ return parsedValue;
209
+ })
210
+ );
211
+ Object.assign(deviceData.Device, settings);
212
+ updateDeviceState = true;
213
+ break;
214
+ case 'unitWifiSignalChanged':
215
+ deviceData.Rssi = messageData.rssi;
216
+ updateDeviceState = true;
217
+ break;
218
+ default:
219
+ if (!this.logDebug) this.emit('debug', `Unit ${unitId}, received unknown message type: ${stringifyMessage}`);
220
+ return;
221
+ }
222
+ break;
223
+ default:
224
+ if (!this.logDebug) this.emit('debug', `Incoming unknown unit id: ${stringifyMessage}`);
225
+ return;
226
+ }
227
+
228
+ if (updateDeviceState) await this.updateState(deviceData);
229
+ });
230
+ } catch (error) {
231
+ if (this.logError) this.emit('error', `Socket connection failed: ${error}`);
232
+ this.cleanupSocket();
233
+ }
234
+ }
235
+ if (this.logDebug) this.emit('debug', `Device Data: ${JSON.stringify(deviceData, null, 2)}`);
236
+ await this.updateState(deviceData);
237
+
238
+ return true;
239
+ } catch (error) {
240
+ throw new Error(`Check state error: ${error.message}`);
241
+ };
242
+ };
243
+
236
244
  async send(accountType, displayType, deviceData, flag, flagData) {
237
245
  try {
238
246
  let method = null
@@ -374,7 +382,7 @@ class MelCloudAta extends EventEmitter {
374
382
  data: payload
375
383
  });
376
384
 
377
- this.updateData(deviceData, updateState);
385
+ await this.updateData(deviceData, updateState);
378
386
  return true;
379
387
  default:
380
388
  return;
@@ -385,9 +393,9 @@ class MelCloudAta extends EventEmitter {
385
393
  }
386
394
  }
387
395
 
388
- updateData(deviceData, updateState = true) {
396
+ async updateData(deviceData, updateState = true) {
389
397
  this.locks = true;
390
- if (updateState) this.emit('deviceState', deviceData);
398
+ if (updateState) await this.updateState(deviceData);
391
399
 
392
400
  setTimeout(() => {
393
401
  this.locks = false
@@ -145,11 +145,7 @@ class MelCloudHome extends EventEmitter {
145
145
 
146
146
  const settingsObject = Object.fromEntries(
147
147
  settingsArray.map(({ name, value }) => {
148
- let parsedValue = value;
149
- if (value === "True") parsedValue = true;
150
- else if (value === "False") parsedValue = false;
151
- else if (!isNaN(value) && value !== "") parsedValue = Number(value);
152
-
148
+ let parsedValue = this.functions.convertValue(value, name);
153
149
  const key = name.charAt(0).toUpperCase() + name.slice(1);
154
150
  return [key, parsedValue];
155
151
  })