homebridge-melcloud-control 4.2.3-beta.8 → 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,6 +1,4 @@
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';
@@ -19,7 +17,8 @@ class MelCloud extends EventEmitter {
19
17
  this.accountFile = accountFile;
20
18
  this.buildingsFile = buildingsFile;
21
19
  this.devicesFile = devicesFile;
22
- this.contextKey = null;
20
+ this.headers = {};
21
+
23
22
  this.functions = new Functions(this.logWarn, this.logError, this.logDebug)
24
23
  .on('warn', warn => this.emit('warn', warn))
25
24
  .on('error', error => this.emit('error', error))
@@ -28,13 +27,9 @@ class MelCloud extends EventEmitter {
28
27
  if (pluginStart) {
29
28
  //lock flags
30
29
  this.locks = {
31
- connect: false,
32
30
  checkDevicesList: false
33
31
  };
34
32
  this.impulseGenerator = new ImpulseGenerator()
35
- .on('connect', () => this.handleWithLock('connect', async () => {
36
- await this.connect(true);
37
- }))
38
33
  .on('checkDevicesList', () => this.handleWithLock('checkDevicesList', async () => {
39
34
  await this.checkDevicesList();
40
35
  }))
@@ -60,18 +55,13 @@ class MelCloud extends EventEmitter {
60
55
  // MELCloud
61
56
  async checkDevicesList() {
62
57
  try {
63
- const devicesList = { State: false, Info: null, Devices: [] }
64
- const headers = {
65
- 'X-MitsContextKey': this.contextKey,
66
- 'Content-Type': 'application/json'
67
- }
68
-
58
+ const devicesList = { State: false, Info: null, Devices: [], Scenes: [] }
69
59
  if (this.logDebug) this.emit('debug', `Scanning for devices...`);
70
60
  const listDevicesData = await axios(ApiUrls.ListDevices, {
71
61
  method: 'GET',
72
62
  baseURL: ApiUrls.BaseURL,
73
63
  timeout: 15000,
74
- headers: headers
64
+ headers: this.headers
75
65
  });
76
66
 
77
67
  if (!listDevicesData || !listDevicesData.data) {
@@ -90,6 +80,7 @@ class MelCloud extends EventEmitter {
90
80
  await this.functions.saveData(this.buildingsFile, buildingsList);
91
81
  if (this.logDebug) this.emit('debug', `Buildings list saved`);
92
82
 
83
+ const devices = [];
93
84
  for (const building of buildingsList) {
94
85
  if (!building.Structure) {
95
86
  this.emit('warn', `Building missing structure: ${building.BuildingName || 'Unnamed'}`);
@@ -110,24 +101,26 @@ class MelCloud extends EventEmitter {
110
101
  // Zamiana ID na string
111
102
  allDevices.forEach(device => {
112
103
  device.DeviceID = String(device.DeviceID);
113
- device.Headers = headers;
104
+ device.Headers = this.headers;
114
105
  });
115
106
 
116
107
  if (this.logDebug) this.emit('debug', `Found ${allDevices.length} devices in building: ${building.Name || 'Unnamed'}`);
117
- devicesList.Devices.push(...allDevices);
108
+ devices.push(...allDevices);
118
109
  }
119
110
 
120
- const devicesCount = devicesList.Devices.length;
111
+ const devicesCount = devices.length;
121
112
  if (devicesCount === 0) {
122
113
  devicesList.Info = 'No devices found'
123
114
  return devicesList;
124
115
  }
125
116
 
126
- await this.functions.saveData(this.devicesFile, devicesList.Devices);
127
- if (this.logDebug) this.emit('debug', `${devicesCount} devices saved`);
128
-
129
117
  devicesList.State = true;
130
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
+
131
124
  return devicesList;
132
125
  } catch (error) {
133
126
  throw new Error(`Check devices list error: ${error.message}`);
@@ -138,7 +131,7 @@ class MelCloud extends EventEmitter {
138
131
  if (this.logDebug) this.emit('debug', `Connecting to MELCloud`);
139
132
 
140
133
  try {
141
- const accountInfo = { State: false, Info: '', LoginData: null, ContextKey: null, UseFahrenheit: false }
134
+ const accountInfo = { State: false, Info: '', LoginData: null, Headers: {}, UseFahrenheit: false }
142
135
 
143
136
  const payload = {
144
137
  Email: this.user,
@@ -174,12 +167,16 @@ class MelCloud extends EventEmitter {
174
167
  accountInfo.Info = 'Context key missing'
175
168
  return accountInfo;
176
169
  }
177
- this.contextKey = contextKey;
170
+
171
+ this.headers = {
172
+ 'X-MitsContextKey': contextKey,
173
+ 'Content-Type': 'application/json'
174
+ };
178
175
 
179
176
  accountInfo.State = true;
180
177
  accountInfo.Info = 'Connect to MELCloud Success';
181
178
  accountInfo.LoginData = loginData;
182
- accountInfo.ContextKey = contextKey;
179
+ accountInfo.Headers = this.headers;
183
180
  await this.functions.saveData(this.accountFile, accountInfo);
184
181
 
185
182
  return accountInfo
@@ -190,18 +187,14 @@ class MelCloud extends EventEmitter {
190
187
 
191
188
  async send(accountInfo) {
192
189
  try {
193
- const axiosInstance = axios.create({
190
+ const payload = { data: accountInfo.LoginData };
191
+ await axios(ApiUrls.UpdateApplicationOptions, {
194
192
  method: 'POST',
195
193
  baseURL: ApiUrls.BaseURL,
196
194
  timeout: 15000,
197
- headers: {
198
- 'X-MitsContextKey': accountInfo.ContextKey,
199
- 'content-type': 'application/json'
200
- }
195
+ headers: accountInfo.Headers,
196
+ data: payload
201
197
  });
202
-
203
- const payload = { data: accountInfo.LoginData };
204
- await axiosInstance(ApiUrls.UpdateApplicationOptions, payload);
205
198
  await this.functions.saveData(this.accountFile, accountInfo);
206
199
  return true;
207
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';
@@ -112,8 +111,13 @@ class MelCloudAta extends EventEmitter {
112
111
  this.emit('mqtt', 'State', deviceData.Device);
113
112
  }
114
113
 
114
+ //check state changes
115
+ const deviceDataHasNotChanged = JSON.stringify(deviceData) === JSON.stringify(this.deviceData);
116
+ if (deviceDataHasNotChanged) return;
117
+ this.deviceData = deviceData;
118
+
115
119
  //emit info
116
- this.emit('deviceInfo', manufacturer, indoor.model, outdoor.model, serialNumber, firmwareAppVersion);
120
+ this.emit('deviceInfo', indoor.model, outdoor.model, serialNumber, firmwareAppVersion);
117
121
 
118
122
  //emit state
119
123
  this.emit('deviceState', deviceData);
@@ -124,7 +128,7 @@ class MelCloudAta extends EventEmitter {
124
128
  };
125
129
  };
126
130
 
127
- async send(accountType, displayType, deviceData, effectiveFlags) {
131
+ async send(accountType, displayType, deviceData, flag, flagData) {
128
132
  try {
129
133
  let method = null
130
134
  let payload = {};
@@ -136,7 +140,7 @@ class MelCloudAta extends EventEmitter {
136
140
  deviceData.Device.SetTemperature = (deviceData.Device.DefaultCoolingSetTemperature + deviceData.Device.DefaultHeatingSetTemperature) / 2;
137
141
  }
138
142
 
139
- deviceData.Device.EffectiveFlags = effectiveFlags;
143
+ deviceData.Device.EffectiveFlags = flag;
140
144
  payload = {
141
145
  DeviceID: deviceData.Device.DeviceID,
142
146
  EffectiveFlags: deviceData.Device.EffectiveFlags,
@@ -179,7 +183,7 @@ class MelCloudAta extends EventEmitter {
179
183
  }
180
184
  }
181
185
 
182
- switch (effectiveFlags) {
186
+ switch (flag) {
183
187
  case 'frostprotection':
184
188
  payload = {
185
189
  enabled: deviceData.FrostProtection.Enabled,
@@ -189,6 +193,7 @@ class MelCloudAta extends EventEmitter {
189
193
  };
190
194
  method = 'POST';
191
195
  path = ApiUrlsHome.PostProtectionFrost;
196
+ deviceData.Headers.Referer = ApiUrlsHome.Referers.PostProtectionFrost.replace('deviceid', deviceData.DeviceID);
192
197
  break;
193
198
  case 'overheatprotection':
194
199
  payload = {
@@ -199,6 +204,7 @@ class MelCloudAta extends EventEmitter {
199
204
  };
200
205
  method = 'POST';
201
206
  path = ApiUrlsHome.PostProtectionOverheat;
207
+ deviceData.Headers.Referer = ApiUrlsHome.Referers.PostProtectionOverheat.replace('deviceid', deviceData.DeviceID);
202
208
  break;
203
209
  case 'holidaymode':
204
210
  payload = {
@@ -209,27 +215,40 @@ class MelCloudAta extends EventEmitter {
209
215
  };
210
216
  method = 'POST';
211
217
  path = ApiUrlsHome.PostHolidayMode;
218
+ deviceData.Headers.Referer = ApiUrlsHome.Referers.PostHolidayMode.replace('deviceid', deviceData.DeviceID);
212
219
  break;
213
220
  case 'schedule':
214
221
  payload = { enabled: deviceData.ScheduleEnabled };
215
222
  method = 'PUT';
216
- 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;
217
231
  break;
218
232
  default:
219
233
  payload = {
220
- Power: deviceData.Device.Power,
221
- SetTemperature: deviceData.Device.SetTemperature,
222
- SetFanSpeed: String(deviceData.Device.SetFanSpeed),
223
- OperationMode: AirConditioner.OperationModeMapEnumToString[deviceData.Device.OperationMode],
224
- VaneHorizontalDirection: AirConditioner.VaneHorizontalDirectionMapEnumToString[deviceData.Device.VaneHorizontalDirection],
225
- 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
226
242
  };
227
243
  method = 'PUT';
228
- path = ApiUrlsHome.SetAta.replace('deviceid', deviceData.DeviceID);
244
+ path = ApiUrlsHome.PutAta.replace('deviceid', deviceData.DeviceID);
245
+ deviceData.Headers.Referer = ApiUrlsHome.Referers.PutDeviceSettings
229
246
  break
230
247
  }
231
248
 
232
- 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)}`);
233
252
  await axios(path, {
234
253
  method: method,
235
254
  baseURL: ApiUrlsHome.BaseURL,
@@ -254,7 +273,7 @@ class MelCloudAta extends EventEmitter {
254
273
 
255
274
  setTimeout(() => {
256
275
  this.lock = false
257
- }, 3000);
276
+ }, 2500);
258
277
  }
259
278
  };
260
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;