homebridge-melcloud-control 4.2.3-beta.7 → 4.2.4

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/src/melcloud.js CHANGED
@@ -1,11 +1,8 @@
1
1
  import axios from 'axios';
2
- import { exec } from 'child_process';
3
- import { promisify } from 'util';
4
2
  import EventEmitter from 'events';
5
3
  import ImpulseGenerator from './impulsegenerator.js';
6
4
  import Functions from './functions.js';
7
- import { ApiUrls, ApiUrlsHome } from './constants.js';
8
- const execPromise = promisify(exec);
5
+ import { ApiUrls } from './constants.js';
9
6
 
10
7
  class MelCloud extends EventEmitter {
11
8
  constructor(account, accountFile, buildingsFile, devicesFile, pluginStart = false) {
@@ -20,7 +17,8 @@ class MelCloud extends EventEmitter {
20
17
  this.accountFile = accountFile;
21
18
  this.buildingsFile = buildingsFile;
22
19
  this.devicesFile = devicesFile;
23
- this.contextKey = null;
20
+ this.headers = {};
21
+
24
22
  this.functions = new Functions(this.logWarn, this.logError, this.logDebug)
25
23
  .on('warn', warn => this.emit('warn', warn))
26
24
  .on('error', error => this.emit('error', error))
@@ -29,13 +27,9 @@ class MelCloud extends EventEmitter {
29
27
  if (pluginStart) {
30
28
  //lock flags
31
29
  this.locks = {
32
- connect: false,
33
30
  checkDevicesList: false
34
31
  };
35
32
  this.impulseGenerator = new ImpulseGenerator()
36
- .on('connect', () => this.handleWithLock('connect', async () => {
37
- await this.connect(true);
38
- }))
39
33
  .on('checkDevicesList', () => this.handleWithLock('checkDevicesList', async () => {
40
34
  await this.checkDevicesList();
41
35
  }))
@@ -61,18 +55,13 @@ class MelCloud extends EventEmitter {
61
55
  // MELCloud
62
56
  async checkDevicesList() {
63
57
  try {
64
- const devicesList = { State: false, Info: null, Devices: [] }
65
- const headers = {
66
- 'X-MitsContextKey': this.contextKey,
67
- 'Content-Type': 'application/json'
68
- }
69
-
58
+ const devicesList = { State: false, Info: null, Devices: [], Scenes: [] }
70
59
  if (this.logDebug) this.emit('debug', `Scanning for devices...`);
71
60
  const listDevicesData = await axios(ApiUrls.ListDevices, {
72
61
  method: 'GET',
73
62
  baseURL: ApiUrls.BaseURL,
74
63
  timeout: 15000,
75
- headers: headers
64
+ headers: this.headers
76
65
  });
77
66
 
78
67
  if (!listDevicesData || !listDevicesData.data) {
@@ -91,6 +80,7 @@ class MelCloud extends EventEmitter {
91
80
  await this.functions.saveData(this.buildingsFile, buildingsList);
92
81
  if (this.logDebug) this.emit('debug', `Buildings list saved`);
93
82
 
83
+ const devices = [];
94
84
  for (const building of buildingsList) {
95
85
  if (!building.Structure) {
96
86
  this.emit('warn', `Building missing structure: ${building.BuildingName || 'Unnamed'}`);
@@ -111,24 +101,26 @@ class MelCloud extends EventEmitter {
111
101
  // Zamiana ID na string
112
102
  allDevices.forEach(device => {
113
103
  device.DeviceID = String(device.DeviceID);
114
- device.Headers = headers;
104
+ device.Headers = this.headers;
115
105
  });
116
106
 
117
107
  if (this.logDebug) this.emit('debug', `Found ${allDevices.length} devices in building: ${building.Name || 'Unnamed'}`);
118
- devicesList.Devices.push(...allDevices);
108
+ devices.push(...allDevices);
119
109
  }
120
110
 
121
- const devicesCount = devicesList.Devices.length;
111
+ const devicesCount = devices.length;
122
112
  if (devicesCount === 0) {
123
113
  devicesList.Info = 'No devices found'
124
114
  return devicesList;
125
115
  }
126
116
 
127
- await this.functions.saveData(this.devicesFile, devicesList.Devices);
128
- if (this.logDebug) this.emit('debug', `${devicesCount} devices saved`);
129
-
130
117
  devicesList.State = true;
131
118
  devicesList.Info = `Found ${devicesCount} devices`;
119
+ devicesList.Devices = devices;
120
+
121
+ await this.functions.saveData(this.devicesFile, devicesList);
122
+ if (this.logDebug) this.emit('debug', `${devicesCount} devices saved`);
123
+
132
124
  return devicesList;
133
125
  } catch (error) {
134
126
  throw new Error(`Check devices list error: ${error.message}`);
@@ -139,7 +131,7 @@ class MelCloud extends EventEmitter {
139
131
  if (this.logDebug) this.emit('debug', `Connecting to MELCloud`);
140
132
 
141
133
  try {
142
- const accountInfo = { State: false, Info: '', LoginData: null, ContextKey: null, UseFahrenheit: false }
134
+ const accountInfo = { State: false, Info: '', LoginData: null, Headers: {}, UseFahrenheit: false }
143
135
 
144
136
  const payload = {
145
137
  Email: this.user,
@@ -175,12 +167,16 @@ class MelCloud extends EventEmitter {
175
167
  accountInfo.Info = 'Context key missing'
176
168
  return accountInfo;
177
169
  }
178
- this.contextKey = contextKey;
170
+
171
+ this.headers = {
172
+ 'X-MitsContextKey': contextKey,
173
+ 'Content-Type': 'application/json'
174
+ };
179
175
 
180
176
  accountInfo.State = true;
181
177
  accountInfo.Info = 'Connect to MELCloud Success';
182
178
  accountInfo.LoginData = loginData;
183
- accountInfo.ContextKey = contextKey;
179
+ accountInfo.Headers = this.headers;
184
180
  await this.functions.saveData(this.accountFile, accountInfo);
185
181
 
186
182
  return accountInfo
@@ -191,18 +187,14 @@ class MelCloud extends EventEmitter {
191
187
 
192
188
  async send(accountInfo) {
193
189
  try {
194
- const axiosInstance = axios.create({
190
+ const payload = { data: accountInfo.LoginData };
191
+ await axios(ApiUrls.UpdateApplicationOptions, {
195
192
  method: 'POST',
196
193
  baseURL: ApiUrls.BaseURL,
197
194
  timeout: 15000,
198
- headers: {
199
- 'X-MitsContextKey': accountInfo.ContextKey,
200
- 'content-type': 'application/json'
201
- }
195
+ headers: accountInfo.Headers,
196
+ data: payload
202
197
  });
203
-
204
- const payload = { data: accountInfo.LoginData };
205
- await axiosInstance(ApiUrls.UpdateApplicationOptions, payload);
206
198
  await this.functions.saveData(this.accountFile, accountInfo);
207
199
  return true;
208
200
  } catch (error) {
@@ -24,7 +24,7 @@ class MelCloudAta extends EventEmitter {
24
24
  //set default values
25
25
  this.deviceData = {};
26
26
 
27
- //lock flags
27
+ //lock flag
28
28
  this.locks = true;
29
29
  this.impulseGenerator = new ImpulseGenerator()
30
30
  .on('checkState', () => this.handleWithLock(async () => {
@@ -52,11 +52,11 @@ class MelCloudAta extends EventEmitter {
52
52
  try {
53
53
  //read device info from file
54
54
  const devicesData = await this.functions.readData(this.devicesFile, true);
55
- const deviceData = devicesData.find(device => device.DeviceID === this.deviceId);
55
+ const scenes = devicesData.Scenes ?? [];
56
+ const deviceData = devicesData.Devices.find(device => device.DeviceID === this.deviceId);
56
57
 
57
58
  if (this.accountType === 'melcloudhome') {
58
- deviceData.SerialNumber = deviceData.DeviceID || '4.0.0';
59
- deviceData.Device.FirmwareAppVersion = deviceData.ConnectedInterfaceIdentifier || '4.0.0';
59
+ deviceData.Scenes = scenes;
60
60
  deviceData.Device.OperationMode = AirConditioner.OperationModeMapStringToEnum[deviceData.Device.OperationMode] ?? deviceData.Device.OperationMode;
61
61
  deviceData.Device.ActualFanSpeed = AirConditioner.FanSpeedMapStringToEnum[deviceData.Device.ActualFanSpeed] ?? deviceData.Device.ActualFanSpeed;
62
62
  deviceData.Device.SetFanSpeed = AirConditioner.FanSpeedMapStringToEnum[deviceData.Device.SetFanSpeed] ?? deviceData.Device.SetFanSpeed;
@@ -76,13 +76,12 @@ class MelCloudAta extends EventEmitter {
76
76
  if (this.logDebug) this.emit('debug', `Device Data: ${JSON.stringify(safeConfig, null, 2)}`);
77
77
 
78
78
  //device
79
- const serialNumber = deviceData.SerialNumber;
80
- const firmwareAppVersion = deviceData.Device?.FirmwareAppVersion;
79
+ const serialNumber = deviceData.SerialNumber || '4.0.0';
80
+ const firmwareAppVersion = deviceData.Device?.FirmwareAppVersion || '4.0.0';
81
81
 
82
82
  //units
83
83
  const units = Array.isArray(deviceData.Device?.Units) ? deviceData.Device?.Units : [];
84
84
  const unitsCount = units.length;
85
- const manufacturer = 'Mitsubishi';
86
85
 
87
86
  const { indoor, outdoor } = units.reduce((acc, unit) => {
88
87
  const target = unit.IsIndoor ? 'indoor' : 'outdoor';
@@ -118,7 +117,7 @@ class MelCloudAta extends EventEmitter {
118
117
  this.deviceData = deviceData;
119
118
 
120
119
  //emit info
121
- this.emit('deviceInfo', manufacturer, indoor.model, outdoor.model, serialNumber, firmwareAppVersion);
120
+ this.emit('deviceInfo', indoor.model, outdoor.model, serialNumber, firmwareAppVersion);
122
121
 
123
122
  //emit state
124
123
  this.emit('deviceState', deviceData);
@@ -129,7 +128,7 @@ class MelCloudAta extends EventEmitter {
129
128
  };
130
129
  };
131
130
 
132
- async send(accountType, displayType, deviceData, effectiveFlags) {
131
+ async send(accountType, displayType, deviceData, flag, flagData) {
133
132
  try {
134
133
  let method = null
135
134
  let payload = {};
@@ -141,7 +140,7 @@ class MelCloudAta extends EventEmitter {
141
140
  deviceData.Device.SetTemperature = (deviceData.Device.DefaultCoolingSetTemperature + deviceData.Device.DefaultHeatingSetTemperature) / 2;
142
141
  }
143
142
 
144
- deviceData.Device.EffectiveFlags = effectiveFlags;
143
+ deviceData.Device.EffectiveFlags = flag;
145
144
  payload = {
146
145
  DeviceID: deviceData.Device.DeviceID,
147
146
  EffectiveFlags: deviceData.Device.EffectiveFlags,
@@ -184,7 +183,7 @@ class MelCloudAta extends EventEmitter {
184
183
  }
185
184
  }
186
185
 
187
- switch (effectiveFlags) {
186
+ switch (flag) {
188
187
  case 'frostprotection':
189
188
  payload = {
190
189
  enabled: deviceData.FrostProtection.Enabled,
@@ -194,6 +193,7 @@ class MelCloudAta extends EventEmitter {
194
193
  };
195
194
  method = 'POST';
196
195
  path = ApiUrlsHome.PostProtectionFrost;
196
+ deviceData.Headers.Referer = ApiUrlsHome.Referers.PostProtectionFrost.replace('deviceid', deviceData.DeviceID);
197
197
  break;
198
198
  case 'overheatprotection':
199
199
  payload = {
@@ -204,6 +204,7 @@ class MelCloudAta extends EventEmitter {
204
204
  };
205
205
  method = 'POST';
206
206
  path = ApiUrlsHome.PostProtectionOverheat;
207
+ deviceData.Headers.Referer = ApiUrlsHome.Referers.PostProtectionOverheat.replace('deviceid', deviceData.DeviceID);
207
208
  break;
208
209
  case 'holidaymode':
209
210
  payload = {
@@ -214,27 +215,40 @@ class MelCloudAta extends EventEmitter {
214
215
  };
215
216
  method = 'POST';
216
217
  path = ApiUrlsHome.PostHolidayMode;
218
+ deviceData.Headers.Referer = ApiUrlsHome.Referers.PostHolidayMode.replace('deviceid', deviceData.DeviceID);
217
219
  break;
218
220
  case 'schedule':
219
221
  payload = { enabled: deviceData.ScheduleEnabled };
220
222
  method = 'PUT';
221
- path = ApiUrlsHome.PutScheduleEnable.replace('deviceid', deviceData.DeviceID);
223
+ path = ApiUrlsHome.PutScheduleEnabled.replace('deviceid', deviceData.DeviceID);
224
+ deviceData.Headers.Referer = ApiUrlsHome.Referers.PutScheduleEnabled.replace('deviceid', deviceData.DeviceID);
225
+ break;
226
+ case 'scene':
227
+ method = 'PUT';
228
+ const state = flagData.Enabled ? 'Enable' : 'Disable';
229
+ path = ApiUrlsHome.PutScene[state].replace('sceneid', flagData.Id);
230
+ deviceData.Headers.Referer = ApiUrlsHome.Referers.GetPutScenes;
222
231
  break;
223
232
  default:
224
233
  payload = {
225
- Power: deviceData.Device.Power,
226
- SetTemperature: deviceData.Device.SetTemperature,
227
- SetFanSpeed: String(deviceData.Device.SetFanSpeed),
228
- OperationMode: AirConditioner.OperationModeMapEnumToString[deviceData.Device.OperationMode],
229
- VaneHorizontalDirection: AirConditioner.VaneHorizontalDirectionMapEnumToString[deviceData.Device.VaneHorizontalDirection],
230
- VaneVerticalDirection: AirConditioner.VaneVerticalDirectionMapEnumToString[deviceData.Device.VaneVerticalDirection],
234
+ power: deviceData.Device.Power,
235
+ setTemperature: deviceData.Device.SetTemperature,
236
+ setFanSpeed: String(deviceData.Device.SetFanSpeed),
237
+ operationMode: AirConditioner.OperationModeMapEnumToString[deviceData.Device.OperationMode],
238
+ vaneHorizontalDirection: AirConditioner.VaneHorizontalDirectionMapEnumToString[deviceData.Device.VaneHorizontalDirection],
239
+ vaneVerticalDirection: AirConditioner.VaneVerticalDirectionMapEnumToString[deviceData.Device.VaneVerticalDirection],
240
+ temperatureIncrementOverride: null,
241
+ inStandbyMode: null
231
242
  };
232
243
  method = 'PUT';
233
- path = ApiUrlsHome.SetAta.replace('deviceid', deviceData.DeviceID);
244
+ path = ApiUrlsHome.PutAta.replace('deviceid', deviceData.DeviceID);
245
+ deviceData.Headers.Referer = ApiUrlsHome.Referers.PutDeviceSettings
234
246
  break
235
247
  }
236
248
 
237
- if (this.logDebug) this.emit('debug', `Send Data: ${JSON.stringify(payload, null, 2)}`);
249
+ deviceData.Headers['Content-Type'] = 'application/json; charset=utf-8';
250
+ deviceData.Headers.Origin = ApiUrlsHome.Origin;
251
+ if (this.logDebug) this.emit('debug', `Send Data: ${JSON.stringify(payload, null, 2)}, Headers: ${JSON.stringify(deviceData.Headers, null, 2)}`);
238
252
  await axios(path, {
239
253
  method: method,
240
254
  baseURL: ApiUrlsHome.BaseURL,
@@ -259,7 +273,7 @@ class MelCloudAta extends EventEmitter {
259
273
 
260
274
  setTimeout(() => {
261
275
  this.lock = false
262
- }, 3000);
276
+ }, 2500);
263
277
  }
264
278
  };
265
279
  export default MelCloudAta;
@@ -52,12 +52,13 @@ class MelCloudAtw extends EventEmitter {
52
52
  try {
53
53
  //read device info from file
54
54
  const devicesData = await this.functions.readData(this.devicesFile, true);
55
- const deviceData = devicesData.find(device => device.DeviceID === this.deviceId);
55
+ const scenes = devicesData.Scenes ?? [];
56
+ const deviceData = devicesData.Devices.find(device => device.DeviceID === this.deviceId);
56
57
 
57
58
  if (this.accountType === 'melcloudhome') {
58
- deviceData.SerialNumber = deviceData.DeviceID || '4.0.0';
59
- deviceData.Device.FirmwareAppVersion = deviceData.ConnectedInterfaceIdentifier || '4.0.0';
59
+ deviceData.Scenes = scenes;
60
60
  }
61
+
61
62
  const safeConfig = {
62
63
  ...deviceData,
63
64
  Headers: 'removed',
@@ -65,15 +66,15 @@ class MelCloudAtw extends EventEmitter {
65
66
  if (this.logDebug) this.emit('debug', `Device Data: ${JSON.stringify(safeConfig, null, 2)}`);
66
67
 
67
68
  //device
68
- const serialNumber = deviceData.SerialNumber;
69
+ //device
70
+ const serialNumber = deviceData.SerialNumber || '4.0.0';
71
+ const firmwareAppVersion = deviceData.Device?.FirmwareAppVersion || '4.0.0';
69
72
  const hasHotWaterTank = deviceData.Device?.HasHotWaterTank;
70
- const firmwareAppVersion = deviceData.Device?.FirmwareAppVersion;
71
73
  const hasZone2 = deviceData.Device?.HasZone2;
72
74
 
73
75
  //units
74
76
  const units = Array.isArray(deviceData.Device?.Units) ? deviceData.Device?.Units : [];
75
77
  const unitsCount = units.length;
76
- const manufacturer = 'Mitsubishi';
77
78
 
78
79
  const { indoor, outdoor } = units.reduce((acc, unit) => {
79
80
  const target = unit.IsIndoor ? 'indoor' : 'outdoor';
@@ -105,11 +106,11 @@ class MelCloudAtw extends EventEmitter {
105
106
 
106
107
  //check state changes
107
108
  const deviceDataHasNotChanged = JSON.stringify(devicesData) === JSON.stringify(this.devicesData);
108
- if (deviceDataHasNotChanged) return;
109
+ if (deviceDataHasNotChanged) return;
109
110
  this.devicesData = devicesData;
110
111
 
111
112
  //emit info
112
- this.emit('deviceInfo', manufacturer, indoor.model, outdoor.model, serialNumber, firmwareAppVersion, hasHotWaterTank, hasZone2);
113
+ this.emit('deviceInfo', indoor.model, outdoor.model, serialNumber, firmwareAppVersion, hasHotWaterTank, hasZone2);
113
114
 
114
115
  //emit state
115
116
  this.emit('deviceState', deviceData);
@@ -120,7 +121,7 @@ class MelCloudAtw extends EventEmitter {
120
121
  };
121
122
  };
122
123
 
123
- async send(accountType, displayType, deviceData, effectiveFlags) {
124
+ async send(accountType, displayType, deviceData, flag, flagData) {
124
125
  try {
125
126
 
126
127
  //prevent to set out of range temp
@@ -141,7 +142,7 @@ class MelCloudAtw extends EventEmitter {
141
142
  let path = '';
142
143
  switch (accountType) {
143
144
  case "melcloud":
144
- deviceData.Device.EffectiveFlags = effectiveFlags;
145
+ deviceData.Device.EffectiveFlags = flag;
145
146
  payload = {
146
147
  DeviceID: deviceData.Device.DeviceID,
147
148
  EffectiveFlags: deviceData.Device.EffectiveFlags,
@@ -176,39 +177,55 @@ class MelCloudAtw extends EventEmitter {
176
177
  this.updateData(deviceData);
177
178
  return true;
178
179
  case "melcloudhome":
179
- switch (effectiveFlags) {
180
+ switch (flag) {
180
181
  case 'holidaymode':
181
- payload = { enabled: deviceData.HolidayMode.Enabled, startDate: deviceData.HolidayMode.StartDate, endDate: deviceData.HolidayMode.EndDate, units: { "ATW": [deviceData.DeviceID] } };
182
+ payload = {
183
+ enabled: deviceData.HolidayMode.Enabled,
184
+ startDate: deviceData.HolidayMode.StartDate,
185
+ endDate: deviceData.HolidayMode.EndDate,
186
+ units: { "ATW": [deviceData.DeviceID] }
187
+ };
182
188
  method = 'POST';
183
189
  path = ApiUrlsHome.PostHolidayMode;
190
+ deviceData.Headers.Referer = ApiUrlsHome.Referers.PostHolidayMode.replace('deviceid', deviceData.DeviceID);
184
191
  break;
185
192
  case 'schedule':
186
193
  payload = { enabled: deviceData.ScheduleEnabled };
187
194
  method = 'PUT';
188
- path = ApiUrlsHome.PutScheduleEnable.replace('deviceid', deviceData.DeviceID);
195
+ path = ApiUrlsHome.PutScheduleEnabled.replace('deviceid', deviceData.DeviceID);
196
+ deviceData.Headers.Referer = ApiUrlsHome.Referers.PutScheduleEnabled.replace('deviceid', deviceData.DeviceID);
197
+ break;
198
+ case 'scene':
199
+ method = 'PUT';
200
+ const state = flagData.Enabled ? 'Enable' : 'Disable';
201
+ path = ApiUrlsHome.PutScene[state].replace('sceneid', flagData.Id);
202
+ deviceData.Headers.Referer = ApiUrlsHome.Referers.GetPutScenes;
189
203
  break;
190
204
  default:
191
205
  payload = {
192
- Power: deviceData.Device.Power,
193
- SetTemperatureZone1: deviceData.Device.SetTemperatureZone1,
194
- SetTemperatureZone2: deviceData.Device.SetTemperatureZone2,
195
- OperationMode: HeatPump.OperationModeMapEnumToString[deviceData.Device.OperationMode],
196
- OperationModeZone1: HeatPump.OperationModeMapEnumToString[deviceData.Device.OperationModeZone1],
197
- OperationModeZone2: HeatPump.OperationModeMapEnumToString[deviceData.Device.OperationModeZone2],
198
- SetHeatFlowTemperatureZone1: deviceData.Device.SetHeatFlowTemperatureZone1,
199
- SetHeatFlowTemperatureZone2: deviceData.Device.SetHeatFlowTemperatureZone2,
200
- SetCoolFlowTemperatureZone1: deviceData.Device.SetCoolFlowTemperatureZone1,
201
- SetCoolFlowTemperatureZone2: deviceData.Device.SetCoolFlowTemperatureZone2,
202
- SetTankWaterTemperature: deviceData.Device.SetTankWaterTemperature,
203
- ForcedHotWaterMode: deviceData.Device.ForcedHotWaterMode,
204
- EcoHotWater: deviceData.Device.EcoHotWater,
206
+ power: deviceData.Device.Power,
207
+ setTemperatureZone1: deviceData.Device.SetTemperatureZone1,
208
+ setTemperatureZone2: deviceData.Device.SetTemperatureZone2,
209
+ operationMode: HeatPump.OperationModeMapEnumToString[deviceData.Device.OperationMode],
210
+ operationModeZone1: HeatPump.OperationModeMapEnumToString[deviceData.Device.OperationModeZone1],
211
+ operationModeZone2: HeatPump.OperationModeMapEnumToString[deviceData.Device.OperationModeZone2],
212
+ opetHeatFlowTemperatureZone1: deviceData.Device.SetHeatFlowTemperatureZone1,
213
+ setHeatFlowTemperatureZone2: deviceData.Device.SetHeatFlowTemperatureZone2,
214
+ setCoolFlowTemperatureZone1: deviceData.Device.SetCoolFlowTemperatureZone1,
215
+ setCoolFlowTemperatureZone2: deviceData.Device.SetCoolFlowTemperatureZone2,
216
+ setTankWaterTemperature: deviceData.Device.SetTankWaterTemperature,
217
+ forcedHotWaterMode: deviceData.Device.ForcedHotWaterMode,
218
+ ecoHotWater: deviceData.Device.EcoHotWater,
205
219
  };
206
220
  method = 'PUT';
207
- path = ApiUrlsHome.SetAtw.replace('deviceid', deviceData.DeviceID);
221
+ path = ApiUrlsHome.PutAtw.replace('deviceid', deviceData.DeviceID);
222
+ deviceData.Headers.Referer = ApiUrlsHome.Referers.PutDeviceSettings
208
223
  break
209
224
  }
210
225
 
211
- if (this.logDebug) this.emit('debug', `Send Data: ${JSON.stringify(payload, null, 2)}`);
226
+ deviceData.Headers['Content-Type'] = 'application/json; charset=utf-8';
227
+ deviceData.Headers.Origin = ApiUrlsHome.Origin;
228
+ if (this.logDebug) this.emit('debug', `Send Data: ${JSON.stringify(payload, null, 2)}, Headers: ${JSON.stringify(deviceData.Headers, null, 2)}`);
212
229
  await axios(path, {
213
230
  method: method,
214
231
  baseURL: ApiUrlsHome.BaseURL,
@@ -233,7 +250,7 @@ class MelCloudAtw extends EventEmitter {
233
250
 
234
251
  setTimeout(() => {
235
252
  this.lock = false
236
- }, 3000);
253
+ }, 2500);
237
254
  }
238
255
  };
239
256
  export default MelCloudAtw;
@@ -52,31 +52,31 @@ class MelCloudErv extends EventEmitter {
52
52
  try {
53
53
  //read device info from file
54
54
  const devicesData = await this.functions.readData(this.devicesFile, true);
55
- const deviceData = devicesData.find(device => device.DeviceID === this.deviceId);
55
+ const scenes = devicesData.Scenes ?? [];
56
+ const deviceData = devicesData.Devices.find(device => device.DeviceID === this.deviceId);
56
57
 
57
58
  if (this.accountType === 'melcloudhome') {
58
- deviceData.SerialNumber = deviceData.DeviceID || '4.0.0';
59
- deviceData.Device.FirmwareAppVersion = deviceData.ConnectedInterfaceIdentifier || '4.0.0';
59
+ deviceData.Scenes = scenes;
60
60
 
61
61
  //read default temps
62
62
  const temps = await this.functions.readData(this.defaultTempsFile, true);
63
63
  deviceData.Device.DefaultHeatingSetTemperature = temps?.defaultHeatingSetTemperature ?? 20;
64
64
  deviceData.Device.DefaultCoolingSetTemperature = temps?.defaultCoolingSetTemperature ?? 24;
65
65
  }
66
+
66
67
  const safeConfig = {
67
68
  ...deviceData,
68
69
  Headers: 'removed',
69
70
  };
70
71
  if (this.logDebug) this.emit('debug', `Device Data: ${JSON.stringify(safeConfig, null, 2)}`);
71
72
 
72
- //presets
73
- const serialNumber = deviceData.SerialNumber;
74
- const firmwareAppVersion = deviceData.Device?.FirmwareAppVersion;
73
+ //device
74
+ const serialNumber = deviceData.SerialNumber || '4.0.0';
75
+ const firmwareAppVersion = deviceData.Device?.FirmwareAppVersion || '4.0.0';
75
76
 
76
77
  //units
77
78
  const units = Array.isArray(deviceData.Device?.Units) ? deviceData.Device?.Units : [];
78
79
  const unitsCount = units.length;
79
- const manufacturer = 'Mitsubishi';
80
80
 
81
81
  const { indoor, outdoor } = units.reduce((acc, unit) => {
82
82
  const target = unit.IsIndoor ? 'indoor' : 'outdoor';
@@ -112,7 +112,7 @@ class MelCloudErv extends EventEmitter {
112
112
  this.devicesData = devicesData;
113
113
 
114
114
  //emit info
115
- this.emit('deviceInfo', manufacturer, indoor.model, outdoor.model, serialNumber, firmwareAppVersion);
115
+ this.emit('deviceInfo', indoor.model, outdoor.model, serialNumber, firmwareAppVersion);
116
116
 
117
117
  //emit state
118
118
  this.emit('deviceState', deviceData);
@@ -123,7 +123,7 @@ class MelCloudErv extends EventEmitter {
123
123
  };
124
124
  };
125
125
 
126
- async send(accountType, displayType, deviceData, effectiveFlags) {
126
+ async send(accountType, displayType, deviceData, flag, flagData) {
127
127
  try {
128
128
  let method = null
129
129
  let payload = {};
@@ -151,7 +151,7 @@ class MelCloudErv extends EventEmitter {
151
151
  };
152
152
 
153
153
  //device state
154
- deviceData.Device.EffectiveFlags = effectiveFlags;
154
+ deviceData.Device.EffectiveFlags = flag;
155
155
  payload = {
156
156
  DeviceID: deviceData.Device.DeviceID,
157
157
  EffectiveFlags: deviceData.Device.EffectiveFlags,
@@ -192,31 +192,47 @@ class MelCloudErv extends EventEmitter {
192
192
  }
193
193
  }
194
194
 
195
- switch (effectiveFlags) {
195
+ switch (flag) {
196
196
  case 'holidaymode':
197
- payload = { enabled: deviceData.HolidayMode.Enabled, startDate: deviceData.HolidayMode.StartDate, endDate: deviceData.HolidayMode.EndDate, units: { "ERV": [deviceData.DeviceID] } };
197
+ payload = {
198
+ enabled: deviceData.HolidayMode.Enabled,
199
+ startDate: deviceData.HolidayMode.StartDate,
200
+ endDate: deviceData.HolidayMode.EndDate,
201
+ units: { "ERV": [deviceData.DeviceID] }
202
+ };
198
203
  method = 'POST';
199
204
  path = ApiUrlsHome.PostHolidayMode;
205
+ deviceData.Headers.Referer = ApiUrlsHome.Referers.PostHolidayMode.replace('deviceid', deviceData.DeviceID);
200
206
  break;
201
207
  case 'schedule':
202
208
  payload = { enabled: deviceData.ScheduleEnabled };
203
209
  method = 'PUT';
204
- path = ApiUrlsHome.PutScheduleEnable.replace('deviceid', deviceData.DeviceID);
210
+ path = ApiUrlsHome.PutScheduleEnabled.replace('deviceid', deviceData.DeviceID);
211
+ deviceData.Headers.Referer = ApiUrlsHome.Referers.PutScheduleEnabled.replace('deviceid', deviceData.DeviceID);
212
+ break;
213
+ case 'scene':
214
+ method = 'PUT';
215
+ const state = flagData.Enabled ? 'Enable' : 'Disable';
216
+ path = ApiUrlsHome.PutScene[state].replace('sceneid', flagData.Id);
217
+ deviceData.Headers.Referer = ApiUrlsHome.Referers.GetPutScenes;
205
218
  break;
206
219
  default:
207
220
  payload = {
208
- Power: deviceData.Device.Power,
209
- SetTemperature: deviceData.Device.SetTemperature,
210
- SetFanSpeed: String(deviceData.Device.SetFanSpeed),
211
- OperationMode: Ventilation.OperationModeMapEnumToString[deviceData.Device.OperationMode],
212
- VentilationMode: Ventilation.VentilationModeMapEnumToString[deviceData.Device.VentilationMode],
221
+ power: deviceData.Device.Power,
222
+ setTemperature: deviceData.Device.SetTemperature,
223
+ setFanSpeed: String(deviceData.Device.SetFanSpeed),
224
+ operationMode: Ventilation.OperationModeMapEnumToString[deviceData.Device.OperationMode],
225
+ ventilationMode: Ventilation.VentilationModeMapEnumToString[deviceData.Device.VentilationMode],
213
226
  };
214
227
  method = 'PUT';
215
- path = ApiUrlsHome.SetErv.replace('deviceid', deviceData.DeviceID);
228
+ path = ApiUrlsHome.PutErv.replace('deviceid', deviceData.DeviceID);
229
+ deviceData.Headers.Referer = ApiUrlsHome.Referers.PutDeviceSettings
216
230
  break
217
231
  }
218
232
 
219
- if (this.logDebug) this.emit('debug', `Send Data: ${JSON.stringify(payload, null, 2)}`);
233
+ deviceData.Headers['Content-Type'] = 'application/json; charset=utf-8';
234
+ deviceData.Headers.Origin = ApiUrlsHome.Origin;
235
+ if (this.logDebug) this.emit('debug', `Send Data: ${JSON.stringify(payload, null, 2)}, Headers: ${JSON.stringify(deviceData.Headers, null, 2)}`);
220
236
  await axios(path, {
221
237
  method: method,
222
238
  baseURL: ApiUrlsHome.BaseURL,
@@ -241,7 +257,7 @@ class MelCloudErv extends EventEmitter {
241
257
 
242
258
  setTimeout(() => {
243
259
  this.lock = false
244
- }, 3000);
260
+ }, 2500);
245
261
  }
246
262
  };
247
263
  export default MelCloudErv;