homebridge-melcloud-control 4.0.0-beta.500 → 4.0.0-beta.502

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/CHANGELOG.md CHANGED
@@ -12,17 +12,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
12
12
  - v1 After update to v1 and above from v0 the devices need to be added to the Home app again and the old unresponsive remove!!! This devices will be removed from all automations and scenes!!!
13
13
  - v2 After update to v2 from v1 only RESTFull and MQTT config settings need to be updated in config.
14
14
  - v2.4 and above require upcomming homebridge v2
15
- - v3 After update to v3 the plugin need to be configured using Config UI X.
16
- - do not configure it manually, always using Config UI X
15
+ - v3 After update to v3 the plugin need to be configured using Homebridge UI.
16
+ - do not configure it manually, always using Homebridge UI
17
17
  - required Homebridge v2.0.0 and above
18
+ - v4 Added support for MELCloud Home.
19
+ - do not use Homebridge UI > v5.5.0 because of brack config.json
18
20
 
19
- ## [4.0.0] - (xx.10.2025)
21
+ ## [4.0.0] - (xx.11.2025)
20
22
 
21
23
  ## Changes
22
24
 
23
25
  - added support for MELCloud Home [#215](https://github.com/grzegorz914/homebridge-melcloud-control/issues/215)
24
- - redme updated
25
26
  - config schema updated
27
+ - redme updated
26
28
  - cleanup
27
29
 
28
30
  ## [3.9.5] - (02.09.2025)
package/README.md CHANGED
@@ -277,21 +277,19 @@ Homebridge plugin for Air Conditioner, Heat Pump and Energy Recovery Ventilation
277
277
  | `refreshInterval` | Here set the background account data refresh time in (sec), default `120s`. |
278
278
  | `log{}` | Log object. |
279
279
  | `log.deviceInfo` | If enabled, log device info will be displayed by every connections device to the network. |
280
- | `log.sSuccess` | If enabled, success log will be displayed in console. |
280
+ | `log.success` | If enabled, success log will be displayed in console. |
281
281
  | `log.info` | If enabled, info log will be displayed in console. |
282
282
  | `log.warn` | If enabled, warn log will be displayed in console. |
283
283
  | `log.error` | If enabled, error log will be displayed in console. |
284
284
  | `log.debug` | If enabled, debug log will be displayed in console. |
285
285
  | `restFul{}` | RSTful object. |
286
286
  | `restFul.enable` | If enabled, RESTful server will start automatically and respond to any path request. |
287
- | `restFul.debug` | If enabled, deep log will be present in homebridge console for RESTFul server. |
288
287
  | `mqtt{}` | MQTT object. |
289
288
  | `mqtt.enable` | If enabled, MQTT Broker will start automatically and publish all awailable PV data. |
290
289
  | `mqtt.host` | Here set the `IP Address` or `Hostname` for MQTT Broker. |
291
290
  | `mqtt.port` | Here set the `Port` for MQTT Broker, default 1883. |
292
291
  | `mqtt.clientId` | Here optional set the `Client Id` of MQTT Broker. |
293
292
  | `mqtt.prefix` | Here set the `Prefix` for `Topic` or leave empty. |
294
- | `mqtt.debug` | If enabled, deep log will be present in homebridge console for MQTT. |
295
293
  | `mqtt.auth{}` | MQTT authorization object. |
296
294
  | `mqtt.auth.enable` | Here enable authorization for MQTT Broker. |
297
295
  | `mqtt.auth.user` | Here set the MQTT Broker user. |
package/index.js CHANGED
@@ -109,8 +109,6 @@ class MelCloudPlatform {
109
109
  if (logLevel.warn) log.warn(`${accountName}, ${accountInfo.Info}`);
110
110
  return;
111
111
  }
112
-
113
- const contextKey = accountInfo.ContextKey;
114
112
  const useFahrenheit = accountInfo.UseFahrenheit;
115
113
 
116
114
  //check devices list
@@ -183,7 +181,7 @@ class MelCloudPlatform {
183
181
 
184
182
  configuredDevice.on('melCloud', async (key, value) => {
185
183
  try {
186
- accountInfo[key] = value;
184
+ accountInfo.LoginData[key] = value;
187
185
  await melCloud.send(accountInfo);
188
186
  } catch (error) {
189
187
  if (logLevel.error) log.error(`${accountName}, ${deviceTypeText}, ${deviceName}, ${error.message ?? error}.`);
@@ -202,7 +200,7 @@ class MelCloudPlatform {
202
200
  if (logLevel.success) log.success(`${accountName}, ${deviceTypeText}, ${deviceName}, Published as external accessory.`);
203
201
 
204
202
  //start impulse generators\
205
- const timmers = accountType === 'melcloudhome' ? [{ name: 'connect', sampling: 300000 }, { name: 'checkDevicesList', sampling: deviceRefreshInterval }] : [{ name: 'checkDevicesList', sampling: refreshInterval }];
203
+ const timmers = accountType === 'melcloudhome' ? [{ name: 'connect', sampling: 600000 }, { name: 'checkDevicesList', sampling: deviceRefreshInterval }] : [{ name: 'checkDevicesList', sampling: refreshInterval }];
206
204
  await melCloud.impulseGenerator.state(true, timmers);
207
205
  await configuredDevice.startStopImpulseGenerator(true, [{ name: 'checkState', sampling: deviceRefreshInterval }]);
208
206
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "displayName": "MELCloud Control",
3
3
  "name": "homebridge-melcloud-control",
4
- "version": "4.0.0-beta.500",
4
+ "version": "4.0.0-beta.502",
5
5
  "description": "Homebridge plugin to control Mitsubishi Air Conditioner, Heat Pump and Energy Recovery Ventilation.",
6
6
  "license": "MIT",
7
7
  "author": "grzegorz914",
package/src/deviceatw.js CHANGED
@@ -1315,10 +1315,10 @@ class DeviceAtw extends EventEmitter {
1315
1315
  //accessory info
1316
1316
  this.manufacturer = manufacturer;
1317
1317
  this.model = modelIndoor ? modelIndoor : modelOutdoor ? modelOutdoor : `${this.deviceTypeText} ${this.deviceId}`;
1318
- this.serialNumber = serialNumber;
1319
- this.firmwareRevision = firmwareAppVersion;
1318
+ this.serialNumber = serialNumber.toString();
1319
+ this.firmwareRevision = firmwareAppVersion.toString();
1320
1320
 
1321
- this.informationService?.setCharacteristic(Characteristic.FirmwareRevision, firmwareAppVersion);
1321
+ this.informationService?.setCharacteristic(Characteristic.FirmwareRevision, this.firmwareAppVersion);
1322
1322
  })
1323
1323
  .on('deviceState', async (deviceData) => {
1324
1324
  this.deviceData = deviceData;
package/src/deviceerv.js CHANGED
@@ -864,10 +864,10 @@ class DeviceErv extends EventEmitter {
864
864
  //accessory info
865
865
  this.manufacturer = manufacturer;
866
866
  this.model = modelIndoor ? modelIndoor : modelOutdoor ? modelOutdoor : `${this.deviceTypeText} ${this.deviceId}`;
867
- this.serialNumber = serialNumber;
868
- this.firmwareRevision = firmwareAppVersion;
867
+ this.serialNumber = serialNumber.toString();
868
+ this.firmwareRevision = firmwareAppVersion.toString();
869
869
 
870
- this.informationService?.setCharacteristic(Characteristic.FirmwareRevision, firmwareAppVersion);
870
+ this.informationService?.setCharacteristic(Characteristic.FirmwareRevision, this.firmwareAppVersion);
871
871
  })
872
872
  .on('deviceState', async (deviceData) => {
873
873
  this.deviceData = deviceData;
package/src/melcloud.js CHANGED
@@ -140,7 +140,7 @@ class MelCloud extends EventEmitter {
140
140
  if (this.logDebug) this.emit('debug', `Connecting to MELCloud`);
141
141
 
142
142
  try {
143
- const accountInfo = { State: false, Info: '', ContextKey: null, UseFahrenheit: false }
143
+ const accountInfo = { State: false, Info: '', LoginData: null, ContextKey: null, UseFahrenheit: false }
144
144
  const axiosInstance = axios.create({
145
145
  method: 'POST',
146
146
  baseURL: ApiUrls.BaseURL,
@@ -486,12 +486,12 @@ class MelCloud extends EventEmitter {
486
486
  baseURL: ApiUrls.BaseURL,
487
487
  timeout: 15000,
488
488
  headers: {
489
- 'X-MitsContextKey': this.contextKey,
489
+ 'X-MitsContextKey': accountInfo.ContextKey,
490
490
  'content-type': 'application/json'
491
491
  }
492
492
  });
493
493
 
494
- const options = { data: accountInfo };
494
+ const options = { data: accountInfo.LoginData };
495
495
  await axiosInstance.post(ApiUrls.UpdateApplicationOptions, options);
496
496
  await this.functions.saveData(this.accountFile, accountInfo);
497
497
  return true;
@@ -7,7 +7,7 @@ import { ApiUrls, ApiUrlsHome, AirConditioner } from './constants.js';
7
7
  class MelCloudAta extends EventEmitter {
8
8
  constructor(account, device, devicesFile, defaultTempsFile) {
9
9
  super();
10
- this.accountType = account.type
10
+ this.accountType = account.type;
11
11
  this.deviceId = device.id;
12
12
  this.logWarn = device.log?.warn;
13
13
  this.logError = device.log?.error;
@@ -50,7 +50,6 @@ class MelCloudAta extends EventEmitter {
50
50
 
51
51
  async checkState() {
52
52
  try {
53
-
54
53
  //read device info from file
55
54
  const devicesData = await this.functions.readData(this.devicesFile, true);
56
55
 
@@ -121,7 +120,6 @@ class MelCloudAta extends EventEmitter {
121
120
  return acc;
122
121
  }, { indoor: {}, outdoor: {} });
123
122
 
124
-
125
123
  //display info if units are not configured in MELCloud service
126
124
  if (unitsCount === 0) {
127
125
  if (this.logDebug) this.emit('debug', `Units are not configured in MELCloud service`);
@@ -7,7 +7,7 @@ import { ApiUrls, ApiUrlsHome, HeatPump } from './constants.js';
7
7
  class MelCloudAtw extends EventEmitter {
8
8
  constructor(account, device, devicesFile, defaultTempsFile) {
9
9
  super();
10
- this.accountType = account.type
10
+ this.accountType = account.type;
11
11
  this.deviceId = device.id;
12
12
  this.logWarn = device.log?.warn;
13
13
  this.logError = device.log?.error;
@@ -58,10 +58,14 @@ class MelCloudAtw extends EventEmitter {
58
58
  return null;
59
59
  }
60
60
  const deviceData = devicesData.find(device => device.DeviceID === this.deviceId);
61
+ if (this.accountType === 'melcloudhome') {
62
+ deviceData.SerialNumber = deviceData.Device.DeviceID || '4.0.0';
63
+ deviceData.Device.FirmwareAppVersion = '4.0.0';
64
+ }
61
65
  if (this.logDebug) this.emit('debug', `Device Data: ${JSON.stringify(deviceData, null, 2)}`);
62
66
 
63
67
  //device info
64
- const serialNumber = deviceData.SerialNumber ?? 'Undefined';
68
+ const serialNumber = deviceData.SerialNumber;
65
69
 
66
70
  //device
67
71
  const device = deviceData.Device ?? {};
@@ -91,7 +95,7 @@ class MelCloudAtw extends EventEmitter {
91
95
  const setCoolFlowTemperatureZone2 = device.SetCoolFlowTemperatureZone2;
92
96
  const idleZone1 = device.IdleZone1 ?? false;
93
97
  const idleZone2 = device.IdleZone2 ?? false;
94
- const firmwareAppVersion = device.FirmwareAppVersion?.toString() ?? 'Undefined';
98
+ const firmwareAppVersion = device.FirmwareAppVersion;
95
99
  const hasZone2 = device.HasZone2 ?? false;
96
100
 
97
101
  //units
@@ -99,55 +103,22 @@ class MelCloudAtw extends EventEmitter {
99
103
  const unitsCount = units.length;
100
104
  const manufacturer = 'Mitsubishi';
101
105
 
102
- //indoor
103
- let idIndoor = 0;
104
- let deviceIndoor = 0;
105
- let serialNumberIndoor = 'Undefined';
106
- let modelNumberIndoor = 0;
107
- let modelIndoor = false;
108
- let typeIndoor = 0;
109
-
110
- //outdoor
111
- let idOutdoor = 0;
112
- let deviceOutdoor = 0;
113
- let serialNumberOutdoor = 'Undefined';
114
- let modelNumberOutdoor = 0;
115
- let modelOutdoor = false;
116
- let typeOutdoor = 0;
117
-
118
- //units array
119
- for (const unit of units) {
120
- const unitId = unit.ID;
121
- const unitDevice = unit.Device;
122
- const unitSerialNumber = unit.SerialNumber ?? 'Undefined';
123
- const unitModelNumber = unit.ModelNumber;
124
- const unitModel = unit.Model ?? false;
125
- const unitType = unit.UnitType;
126
- const unitIsIndoor = unit.IsIndoor ?? false;
127
-
128
- switch (unitIsIndoor) {
129
- case true:
130
- idIndoor = unitId;
131
- deviceIndoor = unitDevice;
132
- serialNumberIndoor = unitSerialNumber;
133
- modelNumberIndoor = unitModelNumber;
134
- modelIndoor = unitModel;
135
- typeIndoor = unitType;
136
- break;
137
- case false:
138
- idOutdoor = unitId;
139
- deviceOutdoor = unitDevice;
140
- serialNumberOutdoor = unitSerialNumber;
141
- modelNumberOutdoor = unitModelNumber;
142
- modelOutdoor = unitModel;
143
- typeOutdoor = unitType;
144
- break;
145
- }
146
- }
106
+ const { indoor, outdoor } = units.reduce((acc, unit) => {
107
+ const target = unit.IsIndoor ? 'indoor' : 'outdoor';
108
+ acc[target] = {
109
+ id: unit.ID,
110
+ device: unit.Device,
111
+ serialNumber: unit.SerialNumber ?? 'Undefined',
112
+ modelNumber: unit.ModelNumber ?? 0,
113
+ model: unit.Model ?? false,
114
+ type: unit.UnitType ?? 0
115
+ };
116
+ return acc;
117
+ }, { indoor: {}, outdoor: {} });
147
118
 
148
119
  //display info if units are not configured in MELCloud service
149
120
  if (unitsCount === 0) {
150
- this.emit('message', `Units are not configured in MELCloud service`);
121
+ if (this.logDebug) this.emit('debug', `Units are not configured in MELCloud service`);
151
122
  };
152
123
 
153
124
  const deviceState = {
@@ -195,7 +166,7 @@ class MelCloudAtw extends EventEmitter {
195
166
  this.deviceState = deviceState;
196
167
 
197
168
  //emit info
198
- this.emit('deviceInfo', manufacturer, modelIndoor, modelOutdoor, serialNumber, firmwareAppVersion, hasHotWaterTank, hasZone2);
169
+ this.emit('deviceInfo', manufacturer, indoor.model, outdoor.model, serialNumber, firmwareAppVersion, hasHotWaterTank, hasZone2);
199
170
 
200
171
  //emit state
201
172
  this.emit('deviceState', deviceData);
@@ -7,7 +7,7 @@ import { ApiUrls, ApiUrlsHome, Ventilation } from './constants.js';
7
7
  class MelCloudErv extends EventEmitter {
8
8
  constructor(account, device, devicesFile, defaultTempsFile) {
9
9
  super();
10
- this.accountType = account.type
10
+ this.accountType = account.type;
11
11
  this.deviceId = device.id;
12
12
  this.logWarn = device.log?.warn;
13
13
  this.logError = device.log?.error;
@@ -58,13 +58,17 @@ class MelCloudErv extends EventEmitter {
58
58
  return null;
59
59
  }
60
60
  const deviceData = devicesData.find(device => device.DeviceID === this.deviceId);
61
+ if (this.accountType === 'melcloudhome') {
62
+ deviceData.SerialNumber = deviceData.Device.DeviceID || '4.0.0';
63
+ deviceData.Device.FirmwareAppVersion = '4.0.0';
64
+ }
61
65
  if (this.logDebug) this.emit('debug', `Device Data: ${JSON.stringify(deviceData, null, 2)}`);
62
66
 
63
67
  //presets
64
68
  const hideRoomTemperature = deviceData.HideRoomTemperature ?? false;
65
69
  const hideSupplyTemperature = deviceData.HideSupplyTemperature ?? false;
66
70
  const hideOutdoorTemperature = deviceData.HideOutdoorTemperature ?? false;
67
- const serialNumber = deviceData.SerialNumber ?? 'Undefined';
71
+ const serialNumber = deviceData.SerialNumber;
68
72
 
69
73
  //device
70
74
  const device = deviceData.Device ?? {};
@@ -87,62 +91,29 @@ class MelCloudErv extends EventEmitter {
87
91
  const ventilationMode = device.VentilationMode; //Lossnay, Bypass, Auto
88
92
  const defaultCoolingSetTemperature = device.DefaultCoolingSetTemperature ?? 23;
89
93
  const defaultHeatingSetTemperature = device.DefaultHeatingSetTemperature ?? 21;
90
- const firmwareAppVersion = device.FirmwareAppVersion?.toString() ?? 'Undefined';
94
+ const firmwareAppVersion = device.FirmwareAppVersion;
91
95
 
92
96
  //units
93
97
  const units = Array.isArray(device.Units) ? device.Units : [];
94
98
  const unitsCount = units.length;
95
99
  const manufacturer = 'Mitsubishi';
96
100
 
97
- //indoor
98
- let idIndoor = 0;
99
- let deviceIndoor = 0;
100
- let serialNumberIndoor = 'Undefined';
101
- let modelNumberIndoor = 0;
102
- let modelIndoor = false;
103
- let typeIndoor = 0;
104
-
105
- //outdoor
106
- let idOutdoor = 0;
107
- let deviceOutdoor = 0;
108
- let serialNumberOutdoor = 'Undefined';
109
- let modelNumberOutdoor = 0;
110
- let modelOutdoor = false;
111
- let typeOutdoor = 0;
112
-
113
- //units array
114
- for (const unit of units) {
115
- const unitId = unit.ID;
116
- const unitDevice = unit.Device;
117
- const unitSerialNumber = unit.SerialNumber ?? 'Undefined';
118
- const unitModelNumber = unit.ModelNumber;
119
- const unitModel = unit.Model ?? false;
120
- const unitType = unit.UnitType;
121
- const unitIsIndoor = unit.IsIndoor ?? false;
122
-
123
- switch (unitIsIndoor) {
124
- case true:
125
- idIndoor = unitId;
126
- deviceIndoor = unitDevice;
127
- serialNumberIndoor = unitSerialNumber;
128
- modelNumberIndoor = unitModelNumber;
129
- modelIndoor = unitModel;
130
- typeIndoor = unitType;
131
- break;
132
- case false:
133
- idOutdoor = unitId;
134
- deviceOutdoor = unitDevice;
135
- serialNumberOutdoor = unitSerialNumber;
136
- modelNumberOutdoor = unitModelNumber;
137
- modelOutdoor = unitModel;
138
- typeOutdoor = unitType;
139
- break;
140
- }
141
- }
101
+ const { indoor, outdoor } = units.reduce((acc, unit) => {
102
+ const target = unit.IsIndoor ? 'indoor' : 'outdoor';
103
+ acc[target] = {
104
+ id: unit.ID,
105
+ device: unit.Device,
106
+ serialNumber: unit.SerialNumber ?? 'Undefined',
107
+ modelNumber: unit.ModelNumber ?? 0,
108
+ model: unit.Model ?? false,
109
+ type: unit.UnitType ?? 0
110
+ };
111
+ return acc;
112
+ }, { indoor: {}, outdoor: {} });
142
113
 
143
114
  //display info if units are not configured in MELCloud service
144
115
  if (unitsCount === 0) {
145
- this.emit('message', `Units are not configured in MELCloud service`);
116
+ if (this.logDebug) this.emit('debug', `Units are not configured in MELCloud service`);
146
117
  };
147
118
 
148
119
  const deviceState = {
@@ -187,7 +158,7 @@ class MelCloudErv extends EventEmitter {
187
158
  this.deviceState = deviceState;
188
159
 
189
160
  //emit info
190
- this.emit('deviceInfo', manufacturer, modelIndoor, modelOutdoor, serialNumber, firmwareAppVersion);
161
+ this.emit('deviceInfo', manufacturer, indoor.model, outdoor.model, serialNumber, firmwareAppVersion);
191
162
 
192
163
  //emit state
193
164
  this.emit('deviceState', deviceData);