homebridge-melcloud-control 4.9.2-beta.1 → 4.9.2-beta.3

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/index.js CHANGED
@@ -112,6 +112,7 @@ class MelCloudPlatform {
112
112
  }
113
113
  if (logLevel.debug) log.info(melCloudDevicesData.Status);
114
114
 
115
+
115
116
  //filter configured devices
116
117
  const devicesIds = (melCloudDevicesData.Devices ?? []).map(d => String(d.DeviceID));
117
118
  const ataDevices = (account.ataDevices || []).filter(d => (d.displayType ?? 0) > 0 && devicesIds.includes(d.id));
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "displayName": "MELCloud Control",
3
3
  "name": "homebridge-melcloud-control",
4
- "version": "4.9.2-beta.1",
4
+ "version": "4.9.2-beta.3",
5
5
  "description": "Homebridge plugin to control Mitsubishi Air Conditioner, Heat Pump and Energy Recovery Ventilation.",
6
6
  "license": "MIT",
7
7
  "author": "grzegorz914",
@@ -40,6 +40,15 @@ class MelCloudHome extends EventEmitter {
40
40
  // Flaga zapobiegająca wielokrotnemu dodaniu interceptorów
41
41
  this.interceptorsAttached = false;
42
42
 
43
+ // WebSocket state
44
+ this.socket = null;
45
+ this.socketConnected = false;
46
+ this.connecting = false;
47
+ this.heartbeat = null;
48
+ this.reconnectTimer = null;
49
+ this.reconnectDelay = 5_000; // ms, rośnie wykładniczo do reconnectDelayMax
50
+ this.reconnectDelayMax = 300_000; // 5 minut
51
+
43
52
  if (pluginStart) {
44
53
  this.impulseGenerator = new ImpulseGenerator()
45
54
  .on('checkDevicesList', async () => {
@@ -53,44 +62,6 @@ class MelCloudHome extends EventEmitter {
53
62
 
54
63
  // ── WebSocket ─────────────────────────────────────────────────────────────
55
64
 
56
- // Pobiera hash do URL WebSocket.
57
- // Sprawdza kolejno: /api/configuration → /api/user/context → access token jako fallback.
58
- // Gdy znajdziesz właściwe źródło, uproszcz tę metodę.
59
- async fetchWsHash() {
60
- // Próba 1: /api/configuration
61
- try {
62
- const resp = await this.client.get(ApiUrls.Home.Get.Config);
63
- const hash = resp.data?.wsHash ?? resp.data?.webSocketHash ?? resp.data?.hash ?? null;
64
- if (hash) {
65
- if (!this.logDebug) this.emit('debug', `WS hash from configuration: ${hash}`);
66
- return hash;
67
- }
68
- if (!this.logDebug) this.emit('debug', `Configuration response (no hash found): ${JSON.stringify(resp.data)}`);
69
- } catch (err) {
70
- if (!this.logDebug) this.emit('debug', `fetchWsHash: configuration failed: ${err.message}`);
71
- }
72
-
73
- // Próba 2: /api/user/context (buildingsList może zawierać hash)
74
- try {
75
- const resp = await this.client.get(ApiUrls.Home.Get.Context);
76
- const hash = resp.data?.wsHash ?? resp.data?.webSocketHash ?? resp.data?.hash ?? null;
77
- if (hash) {
78
- if (!this.logDebug) this.emit('debug', `WS hash from context: ${hash}`);
79
- return hash;
80
- }
81
- } catch (err) {
82
- if (!this.logDebug) this.emit('debug', `fetchWsHash: context failed: ${err.message}`);
83
- }
84
-
85
- // Fallback: access token (JWT) — niektóre implementacje używają go bezpośrednio
86
- if (this.accessToken) {
87
- if (!this.logDebug) this.emit('debug', 'fetchWsHash: falling back to access token as hash');
88
- return this.accessToken;
89
- }
90
-
91
- throw new Error('Unable to obtain WebSocket hash — update fetchWsHash() when source is known');
92
- }
93
-
94
65
  cleanupSocket() {
95
66
  if (this.heartbeat) {
96
67
  clearInterval(this.heartbeat);
@@ -108,11 +79,12 @@ class MelCloudHome extends EventEmitter {
108
79
 
109
80
  let hash;
110
81
  try {
111
- hash = await this.fetchWsHash();
82
+ const resp = await this.client.get(ApiUrls.Home.Get.Context);
83
+ hash = resp.data.id ?? null;
112
84
  } catch (err) {
113
- if (!this.logError) this.emit('error', `connectSocket: cannot get WS hash: ${err.message}`);
85
+ if (this.logError) this.emit('error', `connectSocket: cannot get WS hash: ${err.message}`);
114
86
  this.connecting = false;
115
- this._scheduleReconnect();
87
+ this.scheduleReconnect();
116
88
  return;
117
89
  }
118
90
 
@@ -123,7 +95,7 @@ class MelCloudHome extends EventEmitter {
123
95
  'Cache-Control': 'no-cache',
124
96
  };
125
97
 
126
- if (!this.logDebug) this.emit('debug', `Connecting WebSocket: ${url.slice(0, 60)}...`);
98
+ if (this.logDebug) this.emit('debug', `Connecting WebSocket: ${url.slice(0, 60)}...`);
127
99
 
128
100
  try {
129
101
  const ws = new WebSocket(url, { headers });
@@ -137,16 +109,16 @@ class MelCloudHome extends EventEmitter {
137
109
  ws.on('close', () => {
138
110
  if (this.logDebug) this.emit('debug', 'Web socket closed');
139
111
  this.cleanupSocket();
140
- this._scheduleReconnect();
112
+ this.scheduleReconnect();
141
113
  });
142
114
 
143
115
  ws.on('open', () => {
144
116
  this.socketConnected = true;
145
117
  this.connecting = false;
146
- this._reconnectDelay = 5_000; // reset backoff po udanym połączeniu
147
- if (this._reconnectTimer) {
148
- clearTimeout(this._reconnectTimer);
149
- this._reconnectTimer = null;
118
+ this.reconnectDelay = 5_000; // reset backoff po udanym połączeniu
119
+ if (this.reconnectTimer) {
120
+ clearTimeout(this.reconnectTimer);
121
+ this.reconnectTimer = null;
150
122
  }
151
123
  if (this.logDebug) this.emit('debug', 'Web Socket Connected');
152
124
 
@@ -177,26 +149,25 @@ class MelCloudHome extends EventEmitter {
177
149
  if (this.logError) this.emit('error', `Web socket message parse error: ${err.message}`);
178
150
  }
179
151
  });
180
-
181
152
  } catch (error) {
182
153
  if (this.logError) this.emit('error', `Web socket connection failed: ${error.message}`);
183
154
  this.cleanupSocket();
184
- this._scheduleReconnect();
155
+ this.scheduleReconnect();
185
156
  }
186
157
  }
187
158
 
188
159
  // Wykładniczy backoff: 5s → 10s → 20s → ... → max 5 minut
189
- _scheduleReconnect() {
190
- if (this._reconnectTimer) return; // już zaplanowany
160
+ scheduleReconnect() {
161
+ if (this.reconnectTimer) return; // już zaplanowany
191
162
 
192
- if (this.logDebug) this.emit('debug', `Web socket reconnecting in ${this._reconnectDelay / 1000}s...`);
163
+ if (this.logDebug) this.emit('debug', `Web socket reconnecting in ${this.reconnectDelay / 1000}s...`);
193
164
 
194
- this._reconnectTimer = setTimeout(async () => {
195
- this._reconnectTimer = null;
165
+ this.reconnectTimer = setTimeout(async () => {
166
+ this.reconnectTimer = null;
196
167
  await this.connectSocket();
197
- }, this._reconnectDelay);
168
+ }, this.reconnectDelay);
198
169
 
199
- this._reconnectDelay = Math.min(this._reconnectDelay * 2, this._reconnectDelayMax);
170
+ this.reconnectDelay = Math.min(this.reconnectDelay * 2, this.reconnectDelayMax);
200
171
  }
201
172
 
202
173
  // ── Utils ─────────────────────────────────────────────────────────────────
@@ -458,12 +429,13 @@ class MelCloudHome extends EventEmitter {
458
429
  this.emit('client', this.client);
459
430
  }
460
431
 
461
- connectInfo.State = exchangeRes;
462
- connectInfo.Status = exchangeRes ? 'Connect Success' : 'Connect Failed at token exchange';
463
432
  this.connectSocket().catch(err => {
464
433
  if (this.logError) this.emit('error', `Initial WebSocket connect failed: ${err.message}`);
465
434
  });
466
435
 
436
+ connectInfo.State = exchangeRes;
437
+ connectInfo.Status = `Connect Success${this.socketConnected ? ', Web Socket Connected' : ''}`;
438
+
467
439
  return connectInfo;
468
440
  }
469
441