homebridge-melcloud-control 4.2.3-beta.8 → 4.2.5-beta.0

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