homebridge-melcloud-control 4.1.2-beta.9 → 4.1.2

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/deviceerv.js CHANGED
@@ -31,7 +31,8 @@ class DeviceErv extends EventEmitter {
31
31
  this.temperatureOutdoorSensor = device.temperatureOutdoorSensor || false;
32
32
  this.temperatureSupplySensor = device.temperatureSupplySensor || false;
33
33
  this.errorSensor = device.errorSensor || false;
34
- this.presets = (device.presets || []).filter(preset => (preset.displayType ?? 0) > 0);
34
+ this.presets = this.accountType === 'melcloud' ? (device.presets || []).filter(preset => (preset.displayType ?? 0) > 0 && preset.id !== '0') : [];
35
+ this.schedules = this.accountType === 'melcloudhome' ? (device.schedules || []).filter(schedule => (schedule.displayType ?? 0) > 0 && schedule.id !== '0') : [];
35
36
  this.buttons = (device.buttonsSensors || []).filter(button => (button.displayType ?? 0) > 0);
36
37
  this.deviceId = device.id;
37
38
  this.deviceName = device.name;
@@ -55,6 +56,14 @@ class DeviceErv extends EventEmitter {
55
56
  preset.previousSettings = {};
56
57
  }
57
58
 
59
+ //schedules configured
60
+ for (const schedule of this.schedules) {
61
+ schedule.name = schedule.name || 'Schedule'
62
+ schedule.serviceType = [null, Service.Outlet, Service.Switch, Service.MotionSensor, Service.OccupancySensor, Service.ContactSensor][schedule.displayType];
63
+ schedule.characteristicType = [null, Characteristic.On, Characteristic.On, Characteristic.MotionDetected, Characteristic.OccupancyDetected, Characteristic.ContactSensorState][schedule.displayType];
64
+ schedule.state = false;
65
+ }
66
+
58
67
  //buttons configured
59
68
  for (const button of this.buttons) {
60
69
  button.name = button.name || 'Button'
@@ -230,6 +239,7 @@ class DeviceErv extends EventEmitter {
230
239
  const deviceName = this.deviceName;
231
240
  const accountName = this.accountName;
232
241
  const presetsOnServer = this.accessory.presets;
242
+ const schedulesOnServer = this.accessory.schedules;
233
243
  const hasRoomTemperature = this.accessory.hasRoomTemperature;
234
244
  const hasSupplyTemperature = this.accessory.hasSupplyTemperature;
235
245
  const hasOutdoorTemperature = this.accessory.hasOutdoorTemperature;
@@ -703,14 +713,14 @@ class DeviceErv extends EventEmitter {
703
713
  deviceData.Device.Power = presetData.Power;
704
714
  deviceData.Device.OperationMode = presetData.OperationMode;
705
715
  deviceData.Device.VentilationMode = presetData.VentilationMode;
706
- deviceData.Device.SetFanSpeed = presetData.FanSpeed;
716
+ deviceData.Device.SetFanSpeed = presetData.SetFanSpeed;
707
717
  break;
708
718
  case false:
709
719
  deviceData.Device.SetTemperature = preset.previousSettings.SetTemperature;
710
720
  deviceData.Device.Power = preset.previousSettings.Power;
711
721
  deviceData.Device.OperationMode = preset.previousSettings.OperationMode;
712
722
  deviceData.Device.VentilationMode = preset.previousSettings.VentilationMode;
713
- deviceData.Device.SetFanSpeed = preset.previousSettings.FanSpeed;
723
+ deviceData.Device.SetFanSpeed = preset.previousSettings.SetFanSpeed;
714
724
  break;
715
725
  };
716
726
 
@@ -725,6 +735,42 @@ class DeviceErv extends EventEmitter {
725
735
  accessory.addService(presetService);
726
736
  };
727
737
 
738
+ //schedules services
739
+ if (this.schedules.length > 0) {
740
+ if (this.logDebug) this.emit('debug', `Prepare schedules services`);
741
+ this.schedulesServices = [];
742
+ this.schedules.forEach((schedule, i) => {
743
+ //get preset name
744
+ const name = schedule.name;
745
+
746
+ //get preset name prefix
747
+ const namePrefix = schedule.namePrefix;
748
+
749
+ const serviceName = namePrefix ? `${accessoryName} ${name}` : name;
750
+ const serviceType = schedule.serviceType;
751
+ const characteristicType = schedule.characteristicType;
752
+ const scheduleService = new serviceType(serviceName, `Schedule ${deviceId} ${i}`);
753
+ scheduleService.addOptionalCharacteristic(Characteristic.ConfiguredName);
754
+ scheduleService.setCharacteristic(Characteristic.ConfiguredName, serviceName);
755
+ scheduleService.getCharacteristic(characteristicType)
756
+ .onGet(async () => {
757
+ const state = schedule.state;
758
+ return state;
759
+ })
760
+ .onSet(async (state) => {
761
+ try {
762
+ deviceData.ScheduleEnabled = state;
763
+ await this.melCloudAta.send(this.accountType, this.displayType, deviceData, 'scheduleset');
764
+ if (this.logInfo) this.emit('info', `${state ? 'Set:' : 'Unset:'} ${name}`);
765
+ } catch (error) {
766
+ if (this.logWarn) this.emit('warn', `Set schedule error: ${error}`);
767
+ };
768
+ });
769
+ this.schedulesServices.push(scheduleService);
770
+ accessory.addService(scheduleService);
771
+ });
772
+ };
773
+
728
774
  //buttons services
729
775
  if (this.buttons.length > 0) {
730
776
  if (this.logDebug) this.emit('debug', `Prepare buttons services`);
@@ -882,8 +928,10 @@ class DeviceErv extends EventEmitter {
882
928
  const tempStepKey = this.accountType === 'melcloud' ? 'TemperatureIncrement' : 'HasHalfDegreeIncrements';
883
929
  const errorKey = this.accountType === 'melcloud' ? 'HasError' : 'IsInError';
884
930
 
885
- //presets
886
- const presetsOnServer = deviceData[presetsKey] ?? [];
931
+ //presets schedule
932
+ const scheduleEnabled = deviceData.ScheduleEnabled;
933
+ const schedulesOnServer = deviceData.Schedule ?? [];
934
+ const presetsOnServer = deviceData.Presets ?? [];
887
935
 
888
936
  //device control
889
937
  const hideRoomTemperature = deviceData.HideRoomTemperature;
@@ -934,6 +982,7 @@ class DeviceErv extends EventEmitter {
934
982
  //accessory
935
983
  const obj = {
936
984
  presets: presetsOnServer,
985
+ schedules: schedulesOnServer,
937
986
  hasRoomTemperature: hasRoomTemperature,
938
987
  hasSupplyTemperature: hasSupplyTemperature,
939
988
  hasOutdoorTemperature: hasOutdoorTemperature,
@@ -972,7 +1021,8 @@ class DeviceErv extends EventEmitter {
972
1021
  maxTempCoolDry: maxTempCoolDry,
973
1022
  useFahrenheit: this.useFahrenheit,
974
1023
  temperatureUnit: TemperatureDisplayUnits[this.useFahrenheit],
975
- isInError: isInError
1024
+ isInError: isInError,
1025
+ scheduleEnabled: scheduleEnabled
976
1026
  };
977
1027
 
978
1028
  //ventilation mode - 0, HEAT, 2, COOL, 4, 5, 6, FAN, AUTO
@@ -1121,13 +1171,24 @@ class DeviceErv extends EventEmitter {
1121
1171
  && presetData.SetTemperature === setTemperature
1122
1172
  && presetData.OperationMode === operationMode
1123
1173
  && presetData.VentilationMode === ventilationMode
1124
- && presetData.FanSpeed === setFanSpeed) : false;
1174
+ && presetData.SetFanSpeed === setFanSpeed) : false;
1125
1175
 
1126
1176
  const characteristicType = preset.characteristicType;
1127
1177
  this.presetsServices?.[i]?.updateCharacteristic(characteristicType, preset.state);
1128
1178
  });
1129
1179
  };
1130
1180
 
1181
+ //update schedules state
1182
+ if (this.schedules.length > 0) {
1183
+ this.schedules.forEach((schedule, i) => {
1184
+ const scheduleData = schedulesOnServer.find(s => s[presetsIdKey] === schedule.id);
1185
+ schedule.state = scheduleEnabled; //scheduleData.Enabled : false;
1186
+
1187
+ const characteristicType = schedule.characteristicType;
1188
+ this.schedulesServices?.[i]?.updateCharacteristic(characteristicType, schedule.state);
1189
+ });
1190
+ };
1191
+
1131
1192
  //update buttons state
1132
1193
  if (this.buttons.length > 0) {
1133
1194
  this.buttons.forEach((button, i) => {
package/src/functions.js CHANGED
@@ -68,18 +68,16 @@ class Functions extends EventEmitter {
68
68
  const arch = archOut.trim();
69
69
  if (this.logDebug) this.emit('debug', `Detected architecture: ${arch}`);
70
70
 
71
- // --- Detect Docker environment ---
71
+ // --- Detect Docker ---
72
72
  let isDocker = false;
73
73
  try {
74
- await access('/.dockerenv', fs.constants.F_OK);
75
- isDocker = true;
76
- } catch {
77
- try {
78
- const { stdout } = await execPromise('cat /proc/1/cgroup || true');
79
- if (stdout.includes('docker') || stdout.includes('containerd'))
80
- isDocker = true;
81
- } catch { }
82
- }
74
+ await access('/.dockerenv', fs.constants.F_OK); isDocker = true;
75
+ } catch { }
76
+
77
+ try {
78
+ const { stdout } = await execPromise('cat /proc/1/cgroup || true');
79
+ if (stdout.includes('docker') || stdout.includes('containerd')) isDocker = true;
80
+ } catch { }
83
81
 
84
82
  if (isDocker && this.logDebug) this.emit('debug', 'Running inside Docker container.');
85
83
 
@@ -88,83 +86,68 @@ class Functions extends EventEmitter {
88
86
  chromiumPath = '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome';
89
87
  try {
90
88
  await access(chromiumPath, fs.constants.X_OK);
91
- if (this.logDebug) this.emit('debug', `Using system Chrome at ${chromiumPath}`);
92
89
  return chromiumPath;
93
90
  } catch {
94
91
  return null;
95
92
  }
96
93
  }
97
94
 
98
- // === ARM (e.g. Raspberry Pi) ===
95
+ // === ARM ===
99
96
  if (arch.startsWith('arm')) {
100
97
  try {
101
- await access('/usr/bin/chromium-browser', fs.constants.X_OK);
102
- if (this.logDebug) this.emit('debug', 'Using system Chromium on ARM platform.');
103
- return '/usr/bin/chromium-browser';
98
+ chromiumPath = '/usr/bin/chromium-browser';
99
+ await access(chromiumPath, fs.constants.X_OK);
100
+ return chromiumPath;
104
101
  } catch {
105
- if (this.logWarn) this.emit('warn', 'System Chromium not found on ARM. Attempting installation...');
106
102
  try {
107
103
  await execPromise('sudo apt-get update -y && sudo apt-get install -y chromium-browser chromium-codecs-ffmpeg');
108
- if (this.logDebug) this.emit('debug', 'Chromium installed successfully on ARM.');
109
- return '/usr/bin/chromium-browser';
104
+ return chromiumPath;
110
105
  } catch {
111
106
  return null;
112
107
  }
113
108
  }
114
109
  }
115
110
 
116
- // === Linux (x64, Docker, etc.) ===
111
+ // === Linux x64 ===
117
112
  if (osName === 'Linux') {
113
+ let systemChromium = null;
118
114
  try {
119
- // --- Try detect common Chromium binaries ---
120
115
  const { stdout: checkOut } = await execPromise('which chromium || which chromium-browser || true');
121
- chromiumPath = checkOut.trim();
122
- if (chromiumPath) {
123
- if (this.logDebug) this.emit('debug', `Found system Chromium: ${chromiumPath}`);
124
- return chromiumPath;
125
- }
116
+ systemChromium = checkOut.trim() || null;
126
117
  } catch { }
127
118
 
128
- if (this.logWarn) this.emit('warn', 'Chromium not found. Attempting installation...');
129
-
130
- // --- Try install (Docker-optimized first) ---
131
- const installCommands = [
132
- 'apt-get update -y && apt-get install -y chromium chromium-browser chromium-codecs-ffmpeg',
133
- 'apk add --no-cache chromium ffmpeg',
134
- 'yum install -y chromium chromium-codecs-ffmpeg'
135
- ];
119
+ // --- Detect Entware (QNAP) ---
120
+ let entwareExists = false;
121
+ try {
122
+ await access('/opt/bin/opkg', fs.constants.X_OK);
123
+ entwareExists = true;
124
+ } catch { }
136
125
 
137
- for (const cmd of installCommands) {
126
+ if (entwareExists) {
138
127
  try {
139
- if (this.logDebug) this.emit('debug', `Trying installation: ${cmd}`);
140
- await execPromise(`sudo ${cmd}`);
141
- // Check for binary after install
142
- const { stdout: checkOut } = await execPromise('which chromium || which chromium-browser || true');
143
- chromiumPath = checkOut.trim() || '/usr/bin/chromium';
144
- if (chromiumPath) {
145
- if (this.logDebug) this.emit('debug', `Chromium installed successfully at ${chromiumPath}`);
146
- return chromiumPath;
147
- }
148
- } catch (error) {
149
- if (this.logDebug) this.emit('debug', `Install attempt failed: ${cmd} → ${error.message}`);
150
- }
128
+ await execPromise('/opt/bin/opkg update');
129
+ await execPromise('/opt/bin/opkg install nspr nss libx11 libxcomposite libxdamage libxrandr libatk libatk-bridge libcups libdrm libgbm libasound');
130
+ process.env.LD_LIBRARY_PATH = `/opt/lib:${process.env.LD_LIBRARY_PATH || ''}`;
131
+ } catch { }
151
132
  }
152
133
 
153
- if (isDocker) {
154
- // Docker fallback specific
134
+ // --- Generic Linux installs missing libs for Puppeteer ---
135
+ const depInstall = [
136
+ 'apt-get update -y && apt-get install -y libnspr4 libnss3 libx11-6 libxcomposite1 libxdamage1 libxrandr2 libatk1.0-0 libcups2 libdrm2 libgbm1 libasound2',
137
+ 'apk add --no-cache nspr nss libx11 libxcomposite libxdamage libxrandr atk cups libdrm libgbm alsa-lib',
138
+ 'yum install -y nspr nss libX11 libXcomposite libXdamage libXrandr atk cups libdrm libgbm alsa-lib'
139
+ ];
140
+ for (const cmd of depInstall) {
155
141
  try {
156
- await execPromise('sudo apt-get update -y && sudo apt-get install -y chromium');
157
- await access('/usr/bin/chromium', fs.constants.X_OK);
158
- if (this.logDebug) this.emit('debug', 'Chromium installed successfully inside Docker at /usr/bin/chromium');
159
- return '/usr/bin/chromium';
160
- } catch {
161
- return null;
162
- }
142
+ await execPromise(`sudo ${cmd}`);
143
+ } catch { }
163
144
  }
164
- return null;
145
+
146
+ // Set LD_LIBRARY_PATH so Puppeteer's Chromium can find libs
147
+ process.env.LD_LIBRARY_PATH = `/usr/lib:/usr/lib64:${process.env.LD_LIBRARY_PATH || ''}`;
148
+ return systemChromium;
165
149
  }
166
150
 
167
- // Unknown OS
168
151
  if (this.logDebug) this.emit('debug', `Unsupported OS: ${osName}.`);
169
152
  return null;
170
153
  } catch (error) {
@@ -172,5 +155,6 @@ class Functions extends EventEmitter {
172
155
  return null;
173
156
  }
174
157
  }
158
+
175
159
  }
176
160
  export default Functions
package/src/melcloud.js CHANGED
@@ -1,8 +1,9 @@
1
+ import fs from 'fs';
1
2
  import axios from 'axios';
2
3
  import { exec } from 'child_process';
3
4
  import { promisify } from 'util';
4
5
  import EventEmitter from 'events';
5
- import puppeteer from 'puppeteer-core';
6
+ import puppeteer from 'puppeteer';
6
7
  import ImpulseGenerator from './impulsegenerator.js';
7
8
  import Functions from './functions.js';
8
9
  import { ApiUrls, ApiUrlsHome } from './constants.js';
@@ -235,61 +236,67 @@ class MelCloud extends EventEmitter {
235
236
  if (this.logDebug) this.emit('debug', `Buildings list saved`);
236
237
 
237
238
  const devices = buildingsList.flatMap(building => {
238
- // Rekurencyjna funkcja kapitalizująca klucze w całym obiekcie
239
+ // Funkcja kapitalizująca klucze obiektu
240
+ const capitalizeKeys = obj =>
241
+ Object.fromEntries(
242
+ Object.entries(obj).map(([key, value]) => [
243
+ key.charAt(0).toUpperCase() + key.slice(1),
244
+ value
245
+ ])
246
+ );
247
+
248
+ // Rekurencyjna kapitalizacja kluczy w obiekcie lub tablicy
239
249
  const capitalizeKeysDeep = obj => {
240
- if (Array.isArray(obj)) {
241
- return obj.map(item => capitalizeKeysDeep(item));
242
- } else if (obj && typeof obj === 'object' && obj.constructor === Object) {
250
+ if (Array.isArray(obj)) return obj.map(capitalizeKeysDeep);
251
+ if (obj && typeof obj === 'object') {
243
252
  return Object.fromEntries(
244
- Object.entries(obj).map(([key, value]) => {
245
- const safeKey =
246
- typeof key === 'string'
247
- ? key.charAt(0).toUpperCase() + key.slice(1)
248
- : key;
249
- return [safeKey, capitalizeKeysDeep(value)];
250
- })
253
+ Object.entries(obj).map(([key, value]) => [
254
+ key.charAt(0).toUpperCase() + key.slice(1),
255
+ capitalizeKeysDeep(value)
256
+ ])
251
257
  );
252
258
  }
253
259
  return obj;
254
260
  };
255
261
 
256
262
  // Funkcja tworząca finalny obiekt Device
257
- const createDevice = (device, type, headers = {}) => {
258
- const settingsArray = Array.isArray(device.Settings) ? device.Settings : [];
259
-
260
- // Parsowanie Settings → obiekt z poprawnymi typami i kapitalizacją
261
- const parsedSettings = Object.fromEntries(
262
- settingsArray
263
- .filter(s => s && typeof s.name === 'string')
264
- .map(({ name, value }) => {
265
- let parsedValue = value;
266
- if (value === 'True') parsedValue = true;
267
- else if (value === 'False') parsedValue = false;
268
- else if (
269
- typeof value === 'string' &&
270
- !isNaN(Number(value)) &&
271
- value.trim() !== ''
272
- ) parsedValue = Number(value);
273
-
274
- const key =
275
- name.charAt(0).toUpperCase() + name.slice(1);
276
- return [key, parsedValue];
277
- })
263
+ const createDevice = (device, type) => {
264
+ // Settings już kapitalizowane w nazwach
265
+ const settingsArray = device.Settings || [];
266
+
267
+ const settingsObject = Object.fromEntries(
268
+ settingsArray.map(({ name, value }) => {
269
+ let parsedValue = value;
270
+ if (value === "True") parsedValue = true;
271
+ else if (value === "False") parsedValue = false;
272
+ else if (!isNaN(value) && value !== "") parsedValue = Number(value);
273
+
274
+ const key = name.charAt(0).toUpperCase() + name.slice(1);
275
+ return [key, parsedValue];
276
+ })
278
277
  );
279
278
 
280
- // Połącz Capabilities + Settings + DeviceType
279
+ // Scal Capabilities + Settings + DeviceType w Device
281
280
  const deviceObject = {
282
- ...capitalizeKeysDeep(device.Capabilities || {}),
283
- ...parsedSettings,
281
+ ...capitalizeKeys(device.Capabilities || {}),
282
+ ...settingsObject,
284
283
  DeviceType: type
285
284
  };
286
285
 
287
- // Usuń pola, które nie mają trafić do finalnego obiektu
286
+ // Kapitalizacja brakujących obiektów/tablic
287
+ if (device.FrostProtection) device.FrostProtection = { ...capitalizeKeys(device.FrostProtection || {}) };
288
+ if (device.OverheatProtection) device.OverheatProtection = { ...capitalizeKeys(device.OverheatProtection || {}) };
289
+ if (device.HolidayMode) device.HolidayMode = { ...capitalizeKeys(device.HolidayMode || {}) };
290
+
291
+ if (Array.isArray(device.Schedule)) {
292
+ device.Schedule = device.Schedule.map(capitalizeKeysDeep);
293
+ }
294
+
295
+ // Usuń stare pola Settings i Capabilities
288
296
  const { Settings, Capabilities, Id, GivenDisplayName, ...rest } = device;
289
297
 
290
- // Zwróć gotowy obiekt urządzenia
291
298
  return {
292
- ...capitalizeKeysDeep(rest),
299
+ ...rest,
293
300
  Type: type,
294
301
  DeviceID: Id,
295
302
  DeviceName: GivenDisplayName,
@@ -298,14 +305,11 @@ class MelCloud extends EventEmitter {
298
305
  };
299
306
  };
300
307
 
301
- // Mapowanie urządzeń w budynku
302
308
  return [
303
- ...(building.airToAirUnits || []).map(d => createDevice(capitalizeKeysDeep(d), 0)),
304
- ...(building.airToWaterUnits || []).map(d => createDevice(capitalizeKeysDeep(d), 1)),
305
- ...(building.airToVentilationUnits || []).map(d => createDevice(capitalizeKeysDeep(d), 3))
309
+ ...(building.airToAirUnits || []).map(d => createDevice(capitalizeKeys(d), 0)),
310
+ ...(building.airToWaterUnits || []).map(d => createDevice(capitalizeKeys(d), 1)),
311
+ ...(building.airToVentilationUnits || []).map(d => createDevice(capitalizeKeys(d), 3))
306
312
  ];
307
-
308
-
309
313
  });
310
314
 
311
315
  const devicesCount = devices.length;
@@ -333,7 +337,21 @@ class MelCloud extends EventEmitter {
333
337
  let browser;
334
338
  try {
335
339
  const accountInfo = { State: false, Info: '', ContextKey: null, UseFahrenheit: false };
336
- const chromiumPath = await this.functions.ensureChromiumInstalled();
340
+ let chromiumPath = await this.functions.ensureChromiumInstalled();
341
+
342
+ // === Fallback to Puppeteer's built-in Chromium ===
343
+ if (!chromiumPath) {
344
+ try {
345
+ const puppeteerPath = puppeteer.executablePath();
346
+ if (puppeteerPath && fs.existsSync(puppeteerPath)) {
347
+ chromiumPath = puppeteerPath;
348
+ if (this.logDebug) this.emit('debug', `Using puppeteer Chromium at ${chromiumPath}`);
349
+ }
350
+ } catch { }
351
+ } else {
352
+ if (this.logDebug) this.emit('debug', `Using system Chromium at ${chromiumPath}`);
353
+ }
354
+
337
355
  if (!chromiumPath) {
338
356
  accountInfo.Info = 'Chromium not found on Your device, please install it manually and try again';
339
357
  return accountInfo;
@@ -343,7 +361,6 @@ class MelCloud extends EventEmitter {
343
361
  try {
344
362
  const { stdout } = await execPromise(`"${chromiumPath}" --version`);
345
363
  if (this.logDebug) this.emit('debug', `Chromium detected: ${stdout.trim()}`);
346
- if (this.logDebug) this.emit('debug', `Chromium detected: ${stdout.trim()}`);
347
364
  } catch (error) {
348
365
  accountInfo.Info = `Chromium found at ${chromiumPath}, but cannot be executed: ${error.message}`;
349
366
  return accountInfo;
@@ -23,7 +23,6 @@ class MelCloudAta extends EventEmitter {
23
23
 
24
24
  //set default values
25
25
  this.deviceData = {};
26
- this.headers = {};
27
26
 
28
27
  //lock flags
29
28
  this.locks = {
@@ -60,7 +59,7 @@ class MelCloudAta extends EventEmitter {
60
59
  return null;
61
60
  }
62
61
  const deviceData = devicesData.find(device => device.DeviceID === this.deviceId);
63
- this.headers = deviceData.Headers;
62
+
64
63
  if (this.accountType === 'melcloudhome') {
65
64
  deviceData.SerialNumber = deviceData.DeviceID || '4.0.0';
66
65
  deviceData.Device.FirmwareAppVersion = deviceData.ConnectedInterfaceIdentifier || '4.0.0';
@@ -75,7 +74,12 @@ class MelCloudAta extends EventEmitter {
75
74
  deviceData.Device.DefaultHeatingSetTemperature = temps?.defaultHeatingSetTemperature ?? 20;
76
75
  deviceData.Device.DefaultCoolingSetTemperature = temps?.defaultCoolingSetTemperature ?? 24;
77
76
  }
78
- if (this.logDebug) this.emit('debug', `Device Data: ${JSON.stringify(deviceData, null, 2)}`);
77
+
78
+ const safeConfig = {
79
+ ...deviceData,
80
+ headers: 'removed',
81
+ };
82
+ if (this.logDebug) this.emit('debug', `Device Data: ${JSON.stringify(safeConfig, null, 2)}`);
79
83
 
80
84
  //device
81
85
  const serialNumber = deviceData.SerialNumber;
@@ -144,7 +148,7 @@ class MelCloudAta extends EventEmitter {
144
148
  method: 'POST',
145
149
  baseURL: ApiUrls.BaseURL,
146
150
  timeout: 10000,
147
- headers: this.headers,
151
+ headers: deviceData.Headers,
148
152
  withCredentials: true
149
153
  });
150
154
 
@@ -183,7 +187,7 @@ class MelCloudAta extends EventEmitter {
183
187
  method: 'PUT',
184
188
  baseURL: ApiUrlsHome.BaseURL,
185
189
  timeout: 10000,
186
- headers: this.headers,
190
+ headers: deviceData.Headers,
187
191
  withCredentials: true
188
192
  });
189
193
 
@@ -199,19 +203,19 @@ class MelCloudAta extends EventEmitter {
199
203
  }
200
204
  }
201
205
 
202
- const settings = {
206
+ const settings = effectiveFlags === 'scheduleset' ? { data: { enabled: deviceData.ScheduleEnabled } } : {
203
207
  data: {
204
208
  Power: deviceData.Device.Power,
205
209
  SetTemperature: deviceData.Device.SetTemperature,
206
210
  SetFanSpeed: String(deviceData.Device.SetFanSpeed),
207
211
  OperationMode: AirConditioner.OperationModeMapEnumToString[deviceData.Device.OperationMode],
208
212
  VaneHorizontalDirection: AirConditioner.VaneHorizontalDirectionMapEnumToString[deviceData.Device.VaneHorizontalDirection],
209
- VaneVerticalDirection: AirConditioner.VaneVerticalDirectionMapEnumToString[deviceData.Device.VaneVerticalDirection]
213
+ VaneVerticalDirection: AirConditioner.VaneVerticalDirectionMapEnumToString[deviceData.Device.VaneVerticalDirection],
210
214
  }
211
215
  };
212
216
  if (this.logDebug) this.emit('debug', `Send Data: ${JSON.stringify(settings.data, null, 2)}`);
213
217
 
214
- const path = ApiUrlsHome.SetAta.replace('deviceid', deviceData.DeviceID);
218
+ const path = effectiveFlags === 'scheduleset' ? ApiUrlsHome.SetSchedule.replace('deviceid', deviceData.DeviceID) : ApiUrlsHome.SetAta.replace('deviceid', deviceData.DeviceID);
215
219
  await axiosInstancePut(path, settings);
216
220
  this.updateData(deviceData);
217
221
  return true;
@@ -219,6 +223,11 @@ class MelCloudAta extends EventEmitter {
219
223
  return;
220
224
  }
221
225
  } catch (error) {
226
+ // Return 500 for schedule hovewer working correct
227
+ if (error?.response?.status === 500) {
228
+ return true;
229
+ }
230
+
222
231
  throw new Error(`Send data error: ${error.message}`);
223
232
  }
224
233
  }
@@ -23,7 +23,6 @@ class MelCloudAtw extends EventEmitter {
23
23
 
24
24
  //set default values
25
25
  this.devicesData = {};
26
- this.headers = {};
27
26
 
28
27
  //lock flags
29
28
  this.locks = {
@@ -55,19 +54,21 @@ class MelCloudAtw extends EventEmitter {
55
54
  try {
56
55
  //read device info from file
57
56
  const devicesData = await this.functions.readData(this.devicesFile, true);
58
-
59
57
  if (!Array.isArray(devicesData)) {
60
58
  if (this.logWarn) this.emit('warn', `Device data not found`);
61
59
  return null;
62
60
  }
63
61
  const deviceData = devicesData.find(device => device.DeviceID === this.deviceId);
64
- this.headers = deviceData.Headers;
65
62
 
66
63
  if (this.accountType === 'melcloudhome') {
67
64
  deviceData.SerialNumber = deviceData.DeviceID || '4.0.0';
68
65
  deviceData.Device.FirmwareAppVersion = deviceData.ConnectedInterfaceIdentifier || '4.0.0';
69
66
  }
70
- if (this.logDebug) this.emit('debug', `Device Data: ${JSON.stringify(deviceData, null, 2)}`);
67
+ const safeConfig = {
68
+ ...deviceData,
69
+ headers: 'removed',
70
+ };
71
+ if (this.logDebug) this.emit('debug', `Device Data: ${JSON.stringify(safeConfig, null, 2)}`);
71
72
 
72
73
  //device
73
74
  const serialNumber = deviceData.SerialNumber;
@@ -152,7 +153,7 @@ class MelCloudAtw extends EventEmitter {
152
153
  method: 'POST',
153
154
  baseURL: ApiUrls.BaseURL,
154
155
  timeout: 10000,
155
- headers: this.headers,
156
+ headers: deviceData.Headers,
156
157
  withCredentials: true
157
158
  });
158
159
 
@@ -190,11 +191,11 @@ class MelCloudAtw extends EventEmitter {
190
191
  method: 'PUT',
191
192
  baseURL: ApiUrlsHome.BaseURL,
192
193
  timeout: 10000,
193
- headers: this.headers,
194
+ headers: deviceData.Headers,
194
195
  withCredentials: true
195
196
  });
196
197
 
197
- const settings = {
198
+ const settings = effectiveFlags === 'scheduleset' ? { data: { enabled: deviceData.ScheduleEnabled } } : {
198
199
  data: {
199
200
  Power: deviceData.Device.Power,
200
201
  SetTemperatureZone1: deviceData.Device.SetTemperatureZone1,
@@ -213,7 +214,7 @@ class MelCloudAtw extends EventEmitter {
213
214
  };
214
215
  if (this.logDebug) this.emit('debug', `Send Data: ${JSON.stringify(settings.data, null, 2)}`);
215
216
 
216
- const path = ApiUrlsHome.SetAtw.replace('deviceid', deviceData.DeviceID);
217
+ const path = effectiveFlags === 'scheduleset' ? ApiUrlsHome.SetSchedule.replace('deviceid', deviceData.DeviceID) : ApiUrlsHome.SetAtw.replace('deviceid', deviceData.DeviceID);
217
218
  await axiosInstancePut(path, settings);
218
219
  this.updateData(deviceData);
219
220
  return true;
@@ -221,6 +222,11 @@ class MelCloudAtw extends EventEmitter {
221
222
  return;
222
223
  }
223
224
  } catch (error) {
225
+ // Return 500 for schedule hovewer working correct
226
+ if (error?.response?.status === 500) {
227
+ return true;
228
+ }
229
+
224
230
  throw new Error(`Send data error: ${error.message}`);
225
231
  }
226
232
  }