homebridge-melcloud-control 3.5.0 → 3.5.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
@@ -94,649 +94,156 @@ class DeviceErv extends EventEmitter {
94
94
  this.accessory.temperatureUnit = TemperatureDisplayUnits[this.accessory.useFahrenheit];
95
95
  };
96
96
 
97
- async start() {
97
+ async setOverExternalIntegration(integration, deviceData, key, value) {
98
98
  try {
99
- //melcloud device
100
- this.melCloudErv = new MelCloudErv({
101
- contextKey: this.contextKey,
102
- devicesFile: this.devicesFile,
103
- deviceId: this.deviceId,
104
- debugLog: this.enableDebugMode
105
- });
106
-
107
- this.melCloudErv.on('externalIntegrations', (deviceData) => {
108
- try {
109
- //RESTFul server
110
- const restFulEnabled = this.restFul.enable || false;
111
- if (restFulEnabled) {
112
- if (!this.restFulConnected) {
113
- this.restFul1 = new RestFul({
114
- port: this.deviceId.slice(-4),
115
- debug: this.restFul.debug || false
116
- });
117
-
118
- this.restFul1.on('connected', (message) => {
119
- this.restFulConnected = true;
120
- this.emit('success', message);
121
- })
122
- .on('set', async (key, value) => {
123
- try {
124
- await this.setOverExternalIntegration('RESTFul', deviceData, key, value);
125
- } catch (error) {
126
- this.emit('warn', error);
127
- };
128
- })
129
- .on('debug', (debug) => {
130
- this.emit('debug', debug);
131
- })
132
- .on('error', (error) => {
133
- this.emit('warn', error);
134
- });
135
- }
136
- const restFul0 = this.restFulConnected ? this.restFul1.update('info', deviceData) : false;
137
- const restFul1 = this.restFulConnected ? this.restFul1.update('state', deviceData.Device) : false;
138
- }
139
-
140
- //MQTT client
141
- const mqttEnabled = this.mqtt.enable || false;
142
- if (mqttEnabled) {
143
- if (!this.mqttConnected) {
144
- this.mqtt1 = new Mqtt({
145
- host: this.mqtt.host,
146
- port: this.mqtt.port || 1883,
147
- clientId: `${this.mqtt.clientId}_${this.deviceId}` || `${this.deviceTypeText}_${this.deviceName}_${this.deviceId}`,
148
- prefix: `${this.mqtt.prefix}/${this.deviceTypeText}/${this.deviceName}`,
149
- user: this.mqtt.user,
150
- passwd: this.mqtt.pass,
151
- debug: this.mqtt.debug || false
152
- });
99
+ let set = false
100
+ switch (key) {
101
+ case 'Power':
102
+ deviceData.Device[key] = value;
103
+ deviceData.Device.EffectiveFlags = Ventilation.EffectiveFlags.Power;
104
+ set = await this.melCloudErv.send(deviceData, this.displayMode);
105
+ break;
106
+ case 'OperationMode':
107
+ deviceData.Device[key] = value;
108
+ deviceData.Device.EffectiveFlags = Ventilation.EffectiveFlags.OperationMode;
109
+ set = await this.melCloudErv.send(deviceData, this.displayMode);
110
+ break;
111
+ case 'VentilationMode':
112
+ deviceData.Device[key] = value;
113
+ deviceData.Device.EffectiveFlags = Ventilation.EffectiveFlags.VentilationMode;
114
+ set = await this.melCloudErv.send(deviceData, this.displayMode);
115
+ break;
116
+ case 'SetTemperature':
117
+ deviceData.Device[key] = value;
118
+ deviceData.Device.EffectiveFlags = Ventilation.EffectiveFlags.SetTemperature;
119
+ set = await this.melCloudErv.send(deviceData, this.displayMode);
120
+ break;
121
+ case 'DefaultCoolingSetTemperature':
122
+ deviceData.Device[key] = value;
123
+ deviceData.Device.EffectiveFlags = Ventilation.EffectiveFlags.SetTemperature;
124
+ set = await this.melCloudErv.send(deviceData, this.displayMode);
125
+ break;
126
+ case 'DefaultHeatingSetTemperature':
127
+ deviceData.Device[key] = value;
128
+ deviceData.Device.EffectiveFlags = Ventilation.EffectiveFlags.SetTemperature;
129
+ set = await this.melCloudErv.send(deviceData, this.displayMode);
130
+ break;
131
+ case 'NightPurgeMode':
132
+ deviceData.Device[key] = value;
133
+ deviceData.Device.EffectiveFlags = Ventilation.EffectiveFlags.NightPurgeMode;
134
+ set = await this.melCloudErv.send(deviceData, this.displayMode);
135
+ break;
136
+ case 'SetFanSpeed':
137
+ deviceData.Device[key] = value;
138
+ deviceData.Device.EffectiveFlags = Ventilation.EffectiveFlags.SetFanSpeed;
139
+ set = await this.melCloudErv.send(deviceData, this.displayMode);
140
+ break;
141
+ case 'HideRoomTemperature':
142
+ deviceData[key] = value;
143
+ deviceData.Device.EffectiveFlags = Ventilation.EffectiveFlags.Prohibit;
144
+ set = await this.melCloudErv.send(deviceData, this.displayMode);
145
+ break;
146
+ case 'HideSupplyTemperature':
147
+ deviceData[key] = value;
148
+ deviceData.Device.EffectiveFlags = Ventilation.EffectiveFlags.Prohibit;
149
+ set = await this.melCloudErv.send(deviceData, this.displayMode);
150
+ break;
151
+ case 'HideOutdoorTemperature':
152
+ deviceData[key] = value;
153
+ deviceData.Device.EffectiveFlags = Ventilation.EffectiveFlags.Prohibit;
154
+ set = await this.melCloudErv.send(deviceData, this.displayMode);
155
+ break;
156
+ default:
157
+ this.emit('warn', `${integration}, received key: ${key}, value: ${value}`);
158
+ break;
159
+ };
160
+ return set;
161
+ } catch (error) {
162
+ throw new Error(`${integration} set key: ${key}, value: ${value}, error: ${error.message ?? error}`);
163
+ };
164
+ }
153
165
 
154
- this.mqtt1.on('connected', (message) => {
155
- this.mqttConnected = true;
156
- this.emit('success', message);
157
- })
158
- .on('subscribed', (message) => {
159
- this.emit('success', message);
160
- })
161
- .on('set', async (key, value) => {
162
- try {
163
- await this.setOverExternalIntegration('MQTT', deviceData, key, value);
164
- } catch (error) {
165
- this.emit('warn', error);
166
- };
167
- })
168
- .on('debug', (debug) => {
169
- this.emit('debug', debug);
170
- })
171
- .on('error', (error) => {
172
- this.emit('warn', error);
173
- });
174
- }
175
- const mqtt0 = this.mqttConnected ? this.mqtt1.emit('publish', `Info`, deviceData) : false;
176
- const mqtt1 = this.mqttConnected ? this.mqtt1.emit('publish', `State`, deviceData.Device) : false;
177
- }
178
- } catch (error) {
179
- this.emit('warn', `External integration start error: ${error}.`);
180
- };
181
- })
182
- .on('deviceInfo', (manufacturer, modelIndoor, modelOutdoor, serialNumber, firmwareAppVersion) => {
183
- if (!this.displayDeviceInfo) {
184
- return;
185
- }
166
+ //prepare accessory
167
+ async prepareAccessory(accountInfo, deviceData, deviceId, deviceTypeText, deviceName, accountName) {
168
+ try {
169
+ const presetsOnServer = this.accessory.presets;
170
+ const hasRoomTemperature = this.accessory.hasRoomTemperature;
171
+ const hasSupplyTemperature = this.accessory.hasSupplyTemperature;
172
+ const hasOutdoorTemperature = this.accessory.hasOutdoorTemperature;
173
+ const hasCoolOperationMode = this.accessory.hasCoolOperationMode;
174
+ const hasHeatOperationMode = this.accessory.hasHeatOperationMode;
175
+ const hasAutoVentilationMode = this.accessory.hasAutoVentilationMode;
176
+ const hasBypassVentilationMode = this.accessory.hasBypassVentilationMode;
177
+ const hasAutomaticFanSpeed = this.accessory.hasAutomaticFanSpeed;
178
+ const hasCO2Sensor = this.accessory.hasCO2Sensor;
179
+ const hasPM25Sensor = this.accessory.hasPM25Sensor;
180
+ const numberOfFanSpeeds = this.accessory.numberOfFanSpeeds;
186
181
 
187
- if (!this.disableLogDeviceInfo) {
188
- this.emit('devInfo', `---- ${this.deviceTypeText}: ${this.deviceName} ----`);
189
- this.emit('devInfo', `Account: ${this.accountName}`);
190
- const indoor = modelIndoor ? this.emit('devInfo', `Indoor: ${modelIndoor}`) : false;
191
- const outdoor = modelOutdoor ? this.emit('devInfo', `Outdoor: ${modelOutdoor}`) : false;
192
- this.emit('devInfo', `Serial: ${serialNumber}`);
193
- this.emit('devInfo', `Firmware: ${firmwareAppVersion}`);
194
- this.emit('devInfo', `Manufacturer: ${manufacturer}`);
195
- this.emit('devInfo', '----------------------------------');
196
- };
182
+ //accessory
183
+ const debug = this.enableDebugMode ? this.emit('debug', `Prepare accessory`) : false;
184
+ const accessoryName = deviceName;
185
+ const accessoryUUID = AccessoryUUID.generate(accountName + deviceId.toString());
186
+ const accessoryCategory = Categories.AIR_PURIFIER;
187
+ const accessory = new Accessory(accessoryName, accessoryUUID, accessoryCategory);
197
188
 
198
- //accessory info
199
- this.manufacturer = manufacturer;
200
- this.model = modelIndoor ? modelIndoor : modelOutdoor ? modelOutdoor : `${this.deviceTypeText} ${this.deviceId}`;
201
- this.serialNumber = serialNumber;
202
- this.firmwareRevision = firmwareAppVersion;
203
- this.displayDeviceInfo = false;
204
- })
205
- .on('deviceState', async (deviceData) => {
206
- //presets
207
- const presetsOnServer = deviceData.Presets ?? [];
189
+ //information service
190
+ const debug1 = this.enableDebugMode ? this.emit('debug', `Prepare information service`) : false;
191
+ accessory.getService(Service.AccessoryInformation)
192
+ .setCharacteristic(Characteristic.Manufacturer, this.manufacturer)
193
+ .setCharacteristic(Characteristic.Model, this.model)
194
+ .setCharacteristic(Characteristic.SerialNumber, this.serialNumber)
195
+ .setCharacteristic(Characteristic.FirmwareRevision, this.firmwareRevision)
196
+ .setCharacteristic(Characteristic.ConfiguredName, accessoryName);
208
197
 
209
- //device control
210
- const hideRoomTemperature = deviceData.HideRoomTemperature;
211
- const hideSupplyTemperature = deviceData.HideSupplyTemperature;
212
- const hideOutdoorTemperature = deviceData.HideOutdoorTemperature;
213
-
214
- //device info
215
- const hasCoolOperationMode = deviceData.Device.HasCoolOperationMode ?? false;
216
- const hasHeatOperationMode = deviceData.Device.HasHeatOperationMode ?? false;
217
- const hasAutoOperationMode = deviceData.Device.HasAutoOperationMode ?? false;
218
- const hasRoomTemperature = deviceData.Device.HasRoomTemperature ?? false;
219
- const hasSupplyTemperature = deviceData.Device.HasSupplyTemperature ?? false;
220
- const hasOutdoorTemperature = deviceData.Device.HasOutdoorTemperature ?? false;
221
- const hasCO2Sensor = deviceData.Device.HasCO2Sensor ?? false;
222
- const roomCO2Level = deviceData.Device.RoomCO2Level ?? false;
223
- const roomCO2Detected = hasCO2Sensor && roomCO2Level > 1000 ? true : false;
224
- const hasPM25Sensor = deviceData.Device.HasPM25Sensor ?? false;
225
- const pM25SensorStatus = hasPM25Sensor ? deviceData.Device.PM25SensorStatus : 0;
226
- const pM25Level = hasPM25Sensor ? deviceData.Device.PM25Level : 0;
227
- const pM25AirQuality = hasPM25Sensor ? pM25Level <= 13 ? 1 : pM25Level <= 35 ? 2 : pM25Level <= 55 ? 3 : pM25Level <= 75 ? 4 : pM25Level <= 110 ? 5 : 0 : 0;
228
- const hasAutoVentilationMode = deviceData.Device.HasAutoVentilationMode ?? false;
229
- const hasBypassVentilationMode = deviceData.Device.HasBypassVentilationMode ?? false;
230
- const hasAutomaticFanSpeed = deviceData.Device.HasAutomaticFanSpeed ?? false;
231
- const coreMaintenanceRequired = deviceData.Device.CoreMaintenanceRequired ? 1 : 0;
232
- const filterMaintenanceRequired = deviceData.Device.FilterMaintenanceRequired ? 1 : 0;
233
- const actualVentilationMode = deviceData.Device.ActualVentilationMode;
234
- const numberOfFanSpeeds = deviceData.Device.NumberOfFanSpeeds ?? 0;
235
- const temperatureIncrement = deviceData.Device.TemperatureIncrement ?? 1;
236
- const minTempHeat = 10;
237
- const maxTempHeat = 31;
238
- const minTempCoolDry = 16;
239
- const maxTempCoolDry = 31;
240
-
241
- //device state
242
- const power = deviceData.Device.Power ?? false;
243
- const roomTemperature = deviceData.Device.RoomTemperature;
244
- const supplyTemperature = deviceData.Device.SupplyTemperature;
245
- const outdoorTemperature = deviceData.Device.OutdoorTemperature;
246
- const nightPurgeMode = deviceData.Device.NightPurgeMode;
247
- const setTemperature = deviceData.Device.SetTemperature ?? 20;
248
- const defaultHeatingSetTemperature = deviceData.Device.DefaultHeatingSetTemperature ?? 20;
249
- const defaultCoolingSetTemperature = deviceData.Device.DefaultCoolingSetTemperature ?? 23;
250
- const setFanSpeed = deviceData.Device.SetFanSpeed;
251
- const operationMode = deviceData.Device.OperationMode;
252
- const ventilationMode = deviceData.Device.VentilationMode;
253
-
254
- //accessory
255
- this.accessory.presets = presetsOnServer;
256
- this.accessory.hasRoomTemperature = hasRoomTemperature;
257
- this.accessory.hasSupplyTemperature = hasSupplyTemperature;
258
- this.accessory.hasOutdoorTemperature = hasOutdoorTemperature;
259
- this.accessory.hasCoolOperationMode = hasCoolOperationMode;
260
- this.accessory.hasHeatOperationMode = hasHeatOperationMode;
261
- this.accessory.hasCO2Sensor = hasCO2Sensor;
262
- this.accessory.roomCO2Level = roomCO2Level;
263
- this.accessory.roomCO2Detected = roomCO2Detected;
264
- this.accessory.hasPM25Sensor = hasPM25Sensor;
265
- this.accessory.pM25SensorStatus = pM25SensorStatus;
266
- this.accessory.pM25Level = pM25Level;
267
- this.accessory.pM25AirQuality = pM25AirQuality;
268
- this.accessory.hasAutoVentilationMode = hasAutoVentilationMode;
269
- this.accessory.hasBypassVentilationMode = hasBypassVentilationMode;
270
- this.accessory.hasAutomaticFanSpeed = hasAutomaticFanSpeed;
271
- this.accessory.coreMaintenanceRequired = coreMaintenanceRequired;
272
- this.accessory.filterMaintenanceRequired = filterMaintenanceRequired;
273
- this.accessory.actualVentilationMode = actualVentilationMode;
274
- this.accessory.numberOfFanSpeeds = numberOfFanSpeeds;
275
- this.accessory.power = power ? 1 : 0;
276
- this.accessory.operationMode = operationMode;
277
- this.accessory.ventilationMode = ventilationMode;
278
- this.accessory.roomTemperature = roomTemperature;
279
- this.accessory.supplyTemperature = supplyTemperature;
280
- this.accessory.outdoorTemperature = outdoorTemperature;
281
- this.accessory.setTemperature = setTemperature;
282
- this.accessory.defaultHeatingSetTemperature = defaultHeatingSetTemperature;
283
- this.accessory.defaultCoolingSetTemperature = defaultCoolingSetTemperature;
284
- this.accessory.lockPhysicalControl = 0;
285
- this.accessory.temperatureIncrement = temperatureIncrement;
286
- this.accessory.minTempHeat = minTempHeat;
287
- this.accessory.temperatureIncrement = maxTempHeat;
288
- this.accessory.minTempCoolDry = minTempCoolDry;
289
- this.accessory.maxTempCoolDry = maxTempCoolDry;
290
-
291
- //ventilation mode - 0, HEAT, 2, COOL, 4, 5, 6, FAN, AUTO
292
- switch (this.displayMode) {
293
- case 1: //Heater Cooler
294
- switch (ventilationMode) {
295
- case 0: //LOSSNAY
296
- this.accessory.currentOperationMode = 2; //INACTIVE, IDLE, HEATING, COOLIN
297
- this.accessory.targetOperationMode = 1; //AUTO, HEAT, COOL
298
- break;
299
- case 1: //BYPASS
300
- this.accessory.currentOperationMode = 3;
301
- this.accessory.targetOperationMode = 2;
302
- break;
303
- case 2: //AUTO
304
- switch (actualVentilationMode) {
305
- case 0: //LOSSNAY
306
- this.accessory.currentOperationMode = 2;
307
- break;
308
- case 1: //BYPASS
309
- this.accessory.currentOperationMode = 3;
310
- break;
311
- default:
312
- this.emit('warn', `Unknown actual ventilation mode: ${actualVentilationMode}`);
313
- break;
314
- };
315
- this.accessory.targetOperationMode = 0;
316
- break;
317
- default:
318
- this.emit('warn', `Unknown ventilation mode: ${ventilationMode}`);
319
- break;
320
- };
321
-
322
- this.accessory.currentOperationMode = !power ? 0 : this.accessory.currentOperationMode;
323
- this.accessory.operationModeSetPropsMinValue = hasAutoVentilationMode ? 0 : 1;
324
- this.accessory.operationModeSetPropsMaxValue = hasAutoVentilationMode ? 2 : 2;
325
- this.accessory.operationModeSetPropsValidValues = hasAutoVentilationMode ? (hasBypassVentilationMode ? [0, 1, 2] : [0, 2]) : (hasBypassVentilationMode ? [1, 2] : [2]);
326
-
327
- //fan speed mode
328
- this.accessory.fanSpeedSetPropsMaxValue = 2;
329
- switch (numberOfFanSpeeds) {
330
- case 2: //Fan speed mode 2
331
- this.accessory.fanSpeed = hasAutomaticFanSpeed ? [3, 1, 2][setFanSpeed] : [0, 1, 2][setFanSpeed];
332
- this.accessory.fanSpeedSetPropsMaxValue = hasAutomaticFanSpeed ? 3 : 2;
333
- break;
334
- case 3: //Fan speed mode 3
335
- this.this.accessory.fanSpeed = hasAutomaticFanSpeed ? [4, 1, 2, 3][setFanSpeed] : [0, 1, 2, 3][setFanSpeed];
336
- this.accessory.fanSpeedSetPropsMaxValue = hasAutomaticFanSpeed ? 4 : 3;
337
- break;
338
- case 4: //Fan speed mode 4
339
- this.accessory.fanSpeed = hasAutomaticFanSpeed ? [5, 1, 2, 3, 4][setFanSpeed] : [0, 1, 2, 3, 4][setFanSpeed];
340
- this.accessory.fanSpeedSetPropsMaxValue = hasAutomaticFanSpeed ? 5 : 4;
341
- break;
342
- };
343
-
344
- //update characteristics
345
- if (this.melCloudService) {
346
- this.melCloudService
347
- .updateCharacteristic(Characteristic.Active, power)
348
- .updateCharacteristic(Characteristic.CurrentHeaterCoolerState, this.accessory.currentOperationMode)
349
- .updateCharacteristic(Characteristic.TargetHeaterCoolerState, this.accessory.targetOperationMode)
350
- .updateCharacteristic(Characteristic.CurrentTemperature, roomTemperature)
351
- .updateCharacteristic(Characteristic.RotationSpeed, this.accessory.fanSpeed)
352
- .updateCharacteristic(Characteristic.LockPhysicalControls, this.accessory.lockPhysicalControl)
353
- .updateCharacteristic(Characteristic.TemperatureDisplayUnits, this.accessory.useFahrenheit);
354
- const updateDefCool = hasCoolOperationMode ? this.melCloudService.updateCharacteristic(Characteristic.CoolingThresholdTemperature, defaultCoolingSetTemperature) : false;
355
- const updateDefHeat = hasHeatOperationMode ? this.melCloudService.updateCharacteristic(Characteristic.HeatingThresholdTemperature, defaultHeatingSetTemperature) : false;
356
- };
357
- break;
358
- case 2: //Thermostat
359
- //operation mode - 0, HEAT, 2, COOL, 4, 5, 6, FAN, AUTO
360
- switch (ventilationMode) {
361
- case 0: //LOSSNAY
362
- this.accessory.currentOperationMode = 1; //OFF, HEAT, COOL
363
- this.accessory.targetOperationMode = 1; //OFF, HEAT, COOL, AUTO
364
- break;
365
- case 1: //BYPASS
366
- this.accessory.currentOperationMode = 2;
367
- this.accessory.targetOperationMode = 2;
368
- break;
369
- case 2: //AUTO
370
- switch (actualVentilationMode) {
371
- case 0: //LOSSNAY
372
- this.accessory.currentOperationMode = 1;
373
- break;
374
- case 1: //BYPASS
375
- this.accessory.currentOperationMode = 2;
376
- break;
377
- default:
378
- this.emit('warn', `Unknown actual ventilation mode: ${actualVentilationMode}`);
379
- break;
380
- };
381
- this.accessory.targetOperationMode = 3;
382
- break;
383
- default:
384
- this.emit('warn', `Unknown ventilation mode: ${ventilationMode}`);
385
- break;
386
- };
387
-
388
- this.accessory.currentOperationMode = !power ? 0 : this.accessory.currentOperationMode;
389
- this.accessory.targetOperationMode = !power ? 0 : this.accessory.targetOperationMode;
390
- this.accessory.operationModeSetPropsMinValue = hasAutoVentilationMode ? 0 : 0;
391
- this.accessory.operationModeSetPropsMaxValue = hasAutoVentilationMode ? 3 : 2;
392
- this.accessory.operationModeSetPropsValidValues = hasAutoVentilationMode ? (hasBypassVentilationMode ? [0, 1, 2, 3] : [0, 2, 3]) : (hasBypassVentilationMode ? [0, 1, 2] : [0, 2]);
393
-
394
- //update characteristics
395
- if (this.melCloudService) {
396
- this.melCloudService
397
- .updateCharacteristic(Characteristic.CurrentHeatingCoolingState, this.accessory.currentOperationMode)
398
- .updateCharacteristic(Characteristic.TargetHeatingCoolingState, this.accessory.targetOperationMode)
399
- .updateCharacteristic(Characteristic.CurrentTemperature, roomTemperature)
400
- .updateCharacteristic(Characteristic.TargetTemperature, setTemperature)
401
- .updateCharacteristic(Characteristic.TemperatureDisplayUnits, this.accessory.useFahrenheit);
402
- };
403
- break;
404
- };
405
-
406
- //update temperature sensors
407
- if (this.roomTemperatureSensorService) {
408
- this.roomTemperatureSensorService
409
- .updateCharacteristic(Characteristic.CurrentTemperature, roomTemperature)
410
- };
411
-
412
- if (this.outdoorTemperatureSensorService) {
413
- this.outdoorTemperatureSensorService
414
- .updateCharacteristic(Characteristic.CurrentTemperature, outdoorTemperature)
415
- };
416
-
417
- if (this.supplyTemperatureSensorService) {
418
- this.supplyTemperatureSensorService
419
- .updateCharacteristic(Characteristic.CurrentTemperature, supplyTemperature)
420
- };
421
-
422
- //update core maintenance
423
- if (this.coreMaintenanceService) {
424
- this.coreMaintenanceService
425
- .updateCharacteristic(Characteristic.FilterChangeIndication, coreMaintenanceRequired)
426
- }
427
-
428
- //update filter maintenance
429
- if (this.filterMaintenanceService) {
430
- this.filterMaintenanceService
431
- .updateCharacteristic(Characteristic.FilterChangeIndication, filterMaintenanceRequired)
432
- }
433
-
434
- //update CO2 sensor
435
- if (this.carbonDioxideSensorService) {
436
- this.carbonDioxideSensorService
437
- .updateCharacteristic(Characteristic.CarbonDioxideDetected, roomCO2Detected)
438
- .updateCharacteristic(Characteristic.CarbonDioxideLevel, roomCO2Level)
439
- }
440
-
441
- //update PM2.5 sensor
442
- if (this.airQualitySensorService) {
443
- this.airQualitySensorService
444
- .updateCharacteristic(Characteristic.AirQuality, pM25AirQuality)
445
- .updateCharacteristic(Characteristic.PM2_5Density, pM25Level)
446
- }
447
-
448
- //update presets state
449
- if (this.presetsConfigured.length > 0) {
450
- for (let i = 0; i < this.presetsConfigured.length; i++) {
451
- const preset = this.presetsConfigured[i];
452
- const presetData = presetsOnServer.find(p => p.ID === preset.Id);
453
-
454
- preset.state = presetData ? (presetData.Power === power
455
- && presetData.SetTemperature === setTemperature
456
- && presetData.OperationMode === operationMode
457
- && presetData.VentilationMode === ventilationMode
458
- && presetData.FanSpeed === setFanSpeed) : false;
459
-
460
- if (this.presetsServices) {
461
- const characteristicType = preset.characteristicType;
462
- this.presetsServices[i]
463
- .updateCharacteristic(characteristicType, preset.state)
464
- };
465
- };
466
- };
467
-
468
- //update buttons state
469
- if (this.buttonsConfiguredCount > 0) {
470
- for (let i = 0; i < this.buttonsConfiguredCount; i++) {
471
- const button = this.buttonsConfigured[i];
472
- const mode = button.mode;;
473
- switch (mode) {
474
- case 0: //POWER ON,OFF
475
- button.state = (power === true);
476
- break;
477
- case 1: //OPERATION MODE RECOVERY
478
- button.state = power ? (ventilationMode === 0) : false;
479
- break;
480
- case 2: //OPERATION MODE BYPASS
481
- button.state = power ? (ventilationMode === 1) : false;
482
- break;
483
- case 3: //OPERATION MODE AUTO
484
- button.state = power ? (ventilationMode === 2) : false;
485
- break;
486
- case 4: //NIGHT PURGE MODE
487
- button.state = power ? (nightPurgeMode === true) : false;
488
- break;
489
- case 10: //FAN SPEED MODE AUTO
490
- button.state = power ? (setFanSpeed === 0) : false;
491
- break;
492
- case 11: //FAN SPEED MODE 1
493
- button.state = power ? (setFanSpeed === 1) : false;
494
- break;
495
- case 12: //FAN SPEED MODE 2
496
- button.state = power ? (setFanSpeed === 2) : false;
497
- break;
498
- case 13: //FAN SPEED MODE 3
499
- button.state = power ? (setFanSpeed === 3) : false;
500
- break;
501
- case 14: //FAN SPEED MODE 4
502
- button.state = power ? (setFanSpeed === 4) : false;
503
- break;
504
- case 15: //PHYSICAL LOCK CONTROLS
505
- button.state = (this.accessory.lockPhysicalControl === 1);
506
- break;
507
- case 16: //ROOM TEMP HIDE
508
- button.state = (hideRoomTemperature === true);
509
- break;
510
- case 17: //SUPPLY TEMP HIDE
511
- button.state = (hideSupplyTemperature === true);
512
- break;
513
- case 18: //OUTDOOR TEMP HIDE
514
- button.state = (hideOutdoorTemperature === true);
515
- break;
516
- default: //Unknown button
517
- this.emit('warn', `Unknown button mode: ${mode} detected.`);
518
- break;
519
- };
520
-
521
- //update services
522
- if (this.buttonsServices) {
523
- const characteristicType = button.characteristicType;
524
- this.buttonsServices[i]
525
- .updateCharacteristic(characteristicType, button.state)
526
- };
527
- };
528
- };
529
-
530
- //log current state
531
- if (!this.disableLogInfo) {
532
- this.emit('message', `Power: ${power ? 'ON' : 'OFF'}`);
533
- this.emit('message', `Target ventilation mode: ${Ventilation.OperationMode[ventilationMode]}`);
534
- this.emit('message', `Current ventilation mode: ${Ventilation.OperationMode[actualVentilationMode]}`);
535
- this.emit('message', `Target temperature: ${setTemperature}${this.accessory.temperatureUnit}`);
536
- this.emit('message', `Room temperature: ${roomTemperature}${this.accessory.temperatureUnit}`);
537
- const info1 = hasSupplyTemperature && deviceData.Device.SupplyTemperature !== null ? this.emit('message', `Supply temperature: ${roomTemperature}${this.accessory.temperatureUnit}`) : false;
538
- const info2 = hasOutdoorTemperature && deviceData.Device.OutdoorTemperature !== null ? this.emit('message', `Outdoor temperature: ${roomTemperature}${this.accessory.temperatureUnit}`) : false;
539
- this.emit('message', `Fan speed mode: ${Ventilation.FanSpeed[setFanSpeed]}`);
540
- this.emit('message', `Temperature display unit: ${this.accessory.temperatureUnit}`);
541
- this.emit('message', `Core maintenance: ${Ventilation.CoreMaintenance[coreMaintenanceRequired]}`);
542
- this.emit('message', `Filter maintenance: ${Ventilation.FilterMaintenance[filterMaintenanceRequired]}`);
543
- const info5 = hasCO2Sensor ? this.emit('message', `CO2 detected: ${Ventilation.Co2Detected[roomCO2Detected]}`) : false;
544
- const info6 = hasCO2Sensor ? this.emit('message', `CO2 level: ${roomCO2Level} ppm`) : false;
545
- const info7 = hasPM25Sensor ? this.emit('message', `PM2.5 air quality: ${Ventilation.PM25AirQuality[pM25AirQuality]}`) : false;
546
- const info8 = hasPM25Sensor ? this.emit('message', `PM2.5 level: ${pM25Level} µg/m`) : false;
547
- };
548
-
549
- //start prepare accessory
550
- if (!this.startPrepareAccessory) {
551
- return;
552
- }
553
-
554
- try {
555
- const accessory = await this.prepareAccessory(this.accountInfo, deviceData, this.deviceId, this.deviceTypeText, this.deviceName, this.accountName);
556
- this.emit('publishAccessory', accessory);
557
- this.startPrepareAccessory = false;
558
- } catch (error) {
559
- this.emit('error', error);
560
- };
561
- })
562
- .on('success', (message) => {
563
- this.emit('success', message);
564
- })
565
- .on('message', (message) => {
566
- this.emit('message', message);
567
- })
568
- .on('debug', (debug) => {
569
- this.emit('debug', debug);
570
- })
571
- .on('warn', async (warn) => {
572
- this.emit('warn', warn);
573
- })
574
- .on('error', async (error) => {
575
- this.emit('error', error);
576
- });
577
-
578
- //check state
579
- await this.melCloudErv.checkState();
580
-
581
- //start impule generator
582
- await this.melCloudErv.impulseGenerator.start([{ name: 'checkState', sampling: this.refreshInterval }]);
583
-
584
- return true;
585
- } catch (error) {
586
- throw new Error(`Start error: ${error}`);
587
- };
588
- };
589
-
590
- async setOverExternalIntegration(integration, deviceData, key, value) {
591
- try {
592
- let set = false
593
- switch (key) {
594
- case 'Power':
595
- deviceData.Device[key] = value;
596
- deviceData.Device.EffectiveFlags = Ventilation.EffectiveFlags.Power;
597
- set = await this.melCloudErv.send(deviceData, this.displayMode);
598
- break;
599
- case 'OperationMode':
600
- deviceData.Device[key] = value;
601
- deviceData.Device.EffectiveFlags = Ventilation.EffectiveFlags.OperationMode;
602
- set = await this.melCloudErv.send(deviceData, this.displayMode);
603
- break;
604
- case 'VentilationMode':
605
- deviceData.Device[key] = value;
606
- deviceData.Device.EffectiveFlags = Ventilation.EffectiveFlags.VentilationMode;
607
- set = await this.melCloudErv.send(deviceData, this.displayMode);
608
- break;
609
- case 'SetTemperature':
610
- deviceData.Device[key] = value;
611
- deviceData.Device.EffectiveFlags = Ventilation.EffectiveFlags.SetTemperature;
612
- set = await this.melCloudErv.send(deviceData, this.displayMode);
613
- break;
614
- case 'DefaultCoolingSetTemperature':
615
- deviceData.Device[key] = value;
616
- deviceData.Device.EffectiveFlags = Ventilation.EffectiveFlags.SetTemperature;
617
- set = await this.melCloudErv.send(deviceData, this.displayMode);
618
- break;
619
- case 'DefaultHeatingSetTemperature':
620
- deviceData.Device[key] = value;
621
- deviceData.Device.EffectiveFlags = Ventilation.EffectiveFlags.SetTemperature;
622
- set = await this.melCloudErv.send(deviceData, this.displayMode);
623
- break;
624
- case 'NightPurgeMode':
625
- deviceData.Device[key] = value;
626
- deviceData.Device.EffectiveFlags = Ventilation.EffectiveFlags.NightPurgeMode;
627
- set = await this.melCloudErv.send(deviceData, this.displayMode);
628
- break;
629
- case 'SetFanSpeed':
630
- deviceData.Device[key] = value;
631
- deviceData.Device.EffectiveFlags = Ventilation.EffectiveFlags.SetFanSpeed;
632
- set = await this.melCloudErv.send(deviceData, this.displayMode);
633
- break;
634
- case 'HideRoomTemperature':
635
- deviceData[key] = value;
636
- deviceData.Device.EffectiveFlags = Ventilation.EffectiveFlags.Prohibit;
637
- set = await this.melCloudErv.send(deviceData, this.displayMode);
638
- break;
639
- case 'HideSupplyTemperature':
640
- deviceData[key] = value;
641
- deviceData.Device.EffectiveFlags = Ventilation.EffectiveFlags.Prohibit;
642
- set = await this.melCloudErv.send(deviceData, this.displayMode);
643
- break;
644
- case 'HideOutdoorTemperature':
645
- deviceData[key] = value;
646
- deviceData.Device.EffectiveFlags = Ventilation.EffectiveFlags.Prohibit;
647
- set = await this.melCloudErv.send(deviceData, this.displayMode);
648
- break;
649
- default:
650
- this.emit('warn', `${integration}, received key: ${key}, value: ${value}`);
651
- break;
652
- };
653
- return set;
654
- } catch (error) {
655
- throw new Error(`${integration} set key: ${key}, value: ${value}, error: ${error.message ?? error}`);
656
- };
657
- }
658
-
659
- //prepare accessory
660
- async prepareAccessory(accountInfo, deviceData, deviceId, deviceTypeText, deviceName, accountName) {
661
- try {
662
- const presetsOnServer = this.accessory.presets;
663
- const hasRoomTemperature = this.accessory.hasRoomTemperature;
664
- const hasSupplyTemperature = this.accessory.hasSupplyTemperature;
665
- const hasOutdoorTemperature = this.accessory.hasOutdoorTemperature;
666
- const hasCoolOperationMode = this.accessory.hasCoolOperationMode;
667
- const hasHeatOperationMode = this.accessory.hasHeatOperationMode;
668
- const hasAutoVentilationMode = this.accessory.hasAutoVentilationMode;
669
- const hasBypassVentilationMode = this.accessory.hasBypassVentilationMode;
670
- const hasAutomaticFanSpeed = this.accessory.hasAutomaticFanSpeed;
671
- const hasCO2Sensor = this.accessory.hasCO2Sensor;
672
- const hasPM25Sensor = this.accessory.hasPM25Sensor;
673
- const numberOfFanSpeeds = this.accessory.numberOfFanSpeeds;
674
-
675
- //accessory
676
- const debug = this.enableDebugMode ? this.emit('debug', `Prepare accessory`) : false;
677
- const accessoryName = deviceName;
678
- const accessoryUUID = AccessoryUUID.generate(accountName + deviceId.toString());
679
- const accessoryCategory = Categories.AIR_PURIFIER;
680
- const accessory = new Accessory(accessoryName, accessoryUUID, accessoryCategory);
681
-
682
- //information service
683
- const debug1 = this.enableDebugMode ? this.emit('debug', `Prepare information service`) : false;
684
- accessory.getService(Service.AccessoryInformation)
685
- .setCharacteristic(Characteristic.Manufacturer, this.manufacturer)
686
- .setCharacteristic(Characteristic.Model, this.model)
687
- .setCharacteristic(Characteristic.SerialNumber, this.serialNumber)
688
- .setCharacteristic(Characteristic.FirmwareRevision, this.firmwareRevision)
689
- .setCharacteristic(Characteristic.ConfiguredName, accessoryName);
690
-
691
- //services
692
- const serviceName = `${deviceTypeText} ${accessoryName}`;
693
- switch (this.displayMode) {
694
- case 1: //Heater Cooler
695
- const debug = this.enableDebugMode ? this.emit('debug', `Prepare heather/cooler service`) : false;
696
- this.melCloudService = new Service.HeaterCooler(serviceName, `HeaterCooler ${deviceId}`);
697
- this.melCloudService.getCharacteristic(Characteristic.Active)
698
- .onGet(async () => {
699
- const state = this.accessory.power;
700
- return state;
701
- })
702
- .onSet(async (state) => {
703
- try {
704
- deviceData.Device.Power = [false, true][state];
705
- deviceData.Device.EffectiveFlags = Ventilation.EffectiveFlags.Power;
706
- await this.melCloudErv.send(deviceData, this.displayMode);
707
- const info = this.disableLogInfo ? false : this.emit('message', `Set power: ${state ? 'ON' : 'OFF'}`);
708
- } catch (error) {
709
- this.emit('warn', `Set power error: ${error}`);
710
- };
711
- });
712
- this.melCloudService.getCharacteristic(Characteristic.CurrentHeaterCoolerState)
713
- .onGet(async () => {
714
- const value = this.accessory.currentOperationMode;
715
- return value;
716
- });
717
- this.melCloudService.getCharacteristic(Characteristic.TargetHeaterCoolerState)
718
- .setProps({
719
- minValue: this.accessory.operationModeSetPropsMinValue,
720
- maxValue: this.accessory.operationModeSetPropsMaxValue,
721
- validValues: this.accessory.operationModeSetPropsValidValues
722
- })
723
- .onGet(async () => {
724
- const value = this.accessory.targetOperationMode ?? 0; //LOSSNAY, BYPASS, AUTO
725
- return value;
726
- })
727
- .onSet(async (value) => {
728
- try {
729
- switch (value) {
730
- case 0: //AUTO - AUTO
731
- deviceData.Device.VentilationMode = hasAutoVentilationMode ? 2 : 0;
732
- break;
733
- case 1: //HEAT - LOSSNAY
734
- deviceData.Device.VentilationMode = 0;
735
- break;
736
- case 2: //COOL - BYPASS
737
- deviceData.Device.VentilationMode = hasBypassVentilationMode ? 1 : 0;
738
- break;
739
- };
198
+ //services
199
+ const serviceName = `${deviceTypeText} ${accessoryName}`;
200
+ switch (this.displayMode) {
201
+ case 1: //Heater Cooler
202
+ const debug = this.enableDebugMode ? this.emit('debug', `Prepare heather/cooler service`) : false;
203
+ this.melCloudService = new Service.HeaterCooler(serviceName, `HeaterCooler ${deviceId}`);
204
+ this.melCloudService.getCharacteristic(Characteristic.Active)
205
+ .onGet(async () => {
206
+ const state = this.accessory.power;
207
+ return state;
208
+ })
209
+ .onSet(async (state) => {
210
+ try {
211
+ deviceData.Device.Power = [false, true][state];
212
+ deviceData.Device.EffectiveFlags = Ventilation.EffectiveFlags.Power;
213
+ await this.melCloudErv.send(deviceData, this.displayMode);
214
+ const info = this.disableLogInfo ? false : this.emit('message', `Set power: ${state ? 'ON' : 'OFF'}`);
215
+ } catch (error) {
216
+ this.emit('warn', `Set power error: ${error}`);
217
+ };
218
+ });
219
+ this.melCloudService.getCharacteristic(Characteristic.CurrentHeaterCoolerState)
220
+ .onGet(async () => {
221
+ const value = this.accessory.currentOperationMode;
222
+ return value;
223
+ });
224
+ this.melCloudService.getCharacteristic(Characteristic.TargetHeaterCoolerState)
225
+ .setProps({
226
+ minValue: this.accessory.operationModeSetPropsMinValue,
227
+ maxValue: this.accessory.operationModeSetPropsMaxValue,
228
+ validValues: this.accessory.operationModeSetPropsValidValues
229
+ })
230
+ .onGet(async () => {
231
+ const value = this.accessory.targetOperationMode ?? 0; //LOSSNAY, BYPASS, AUTO
232
+ return value;
233
+ })
234
+ .onSet(async (value) => {
235
+ try {
236
+ switch (value) {
237
+ case 0: //AUTO - AUTO
238
+ deviceData.Device.VentilationMode = hasAutoVentilationMode ? 2 : 0;
239
+ break;
240
+ case 1: //HEAT - LOSSNAY
241
+ deviceData.Device.VentilationMode = 0;
242
+ break;
243
+ case 2: //COOL - BYPASS
244
+ deviceData.Device.VentilationMode = hasBypassVentilationMode ? 1 : 0;
245
+ break;
246
+ };
740
247
 
741
248
  deviceData.Device.EffectiveFlags = Ventilation.EffectiveFlags.VentilationMode;
742
249
  await this.melCloudErv.send(deviceData, this.displayMode);
@@ -854,414 +361,908 @@ class DeviceErv extends EventEmitter {
854
361
  // });
855
362
  this.melCloudService.getCharacteristic(Characteristic.TemperatureDisplayUnits)
856
363
  .onGet(async () => {
857
- const value = this.accessory.useFahrenheit;
858
- return value;
364
+ const value = this.accessory.useFahrenheit;
365
+ return value;
366
+ })
367
+ .onSet(async (value) => {
368
+ try {
369
+ accountInfo.UseFahrenheit = [false, true][value];
370
+ await this.melCloud.send(accountInfo);
371
+ this.accessory.useFahrenheit = value;
372
+ const info = this.disableLogInfo ? false : this.emit('message', `Set temperature display unit: ${TemperatureDisplayUnits[value]}`);
373
+ } catch (error) {
374
+ this.emit('warn', `Set temperature display unit error: ${error}`);
375
+ };
376
+ });
377
+ accessory.addService(this.melCloudService);
378
+ break;
379
+ case 2: //Thermostat
380
+ const debug1 = this.enableDebugMode ? this.emit('debug', `Prepare thermostat service`) : false;
381
+ this.melCloudService = new Service.Thermostat(serviceName, `Thermostat ${deviceId}`);
382
+ this.melCloudService.getCharacteristic(Characteristic.CurrentHeatingCoolingState)
383
+ .onGet(async () => {
384
+ const value = this.accessory.currentOperationMode;
385
+ return value;
386
+ });
387
+ this.melCloudService.getCharacteristic(Characteristic.TargetHeatingCoolingState)
388
+ .setProps({
389
+ minValue: this.accessory.operationModeSetPropsMinValue,
390
+ maxValue: this.accessory.operationModeSetPropsMaxValue,
391
+ validValues: this.accessory.operationModeSetPropsValidValues
392
+ })
393
+ .onGet(async () => {
394
+ const value = this.accessory.targetOperationMode ?? 0; //LOSSNAY, BYPASS, AUTO
395
+ return value;
396
+ })
397
+ .onSet(async (value) => {
398
+ try {
399
+ switch (value) {
400
+ case 0: //OFF - POWER OFF
401
+ deviceData.Device.Power = false;
402
+ deviceData.Device.EffectiveFlags = Ventilation.EffectiveFlags.Power;
403
+ break;
404
+ case 1: //HEAT - LOSSNAY
405
+ deviceData.Device.Power = true;
406
+ deviceData.Device.VentilationMode = 0;
407
+ deviceData.Device.EffectiveFlags = Ventilation.EffectiveFlags.Power + Ventilation.EffectiveFlags.VentilationMode;
408
+ break;
409
+ case 2: //COOL - BYPASS
410
+ deviceData.Device.Power = true;
411
+ deviceData.Device.VentilationMode = hasBypassVentilationMode ? 1 : 0;
412
+ deviceData.Device.EffectiveFlags = Ventilation.EffectiveFlags.Power + Ventilation.EffectiveFlags.VentilationMode;
413
+ break;
414
+ case 3: //AUTO - AUTO
415
+ deviceData.Device.Power = true;
416
+ deviceData.Device.VentilationMode = hasAutoVentilationMode ? 2 : 0;
417
+ deviceData.Device.EffectiveFlags = Ventilation.EffectiveFlags.Power + Ventilation.EffectiveFlags.VentilationMode;
418
+ break;
419
+ };
420
+
421
+ await this.melCloudErv.send(deviceData, this.displayMode);
422
+ const operationModeText = Ventilation.VentilationMode[deviceData.Device.VentilationMode];
423
+ const info = this.disableLogInfo ? false : this.emit('message', `Set operation mode: ${operationModeText}`);
424
+ } catch (error) {
425
+ this.emit('warn', `Set operation mode error: ${error}`);
426
+ };
427
+ });
428
+ this.melCloudService.getCharacteristic(Characteristic.CurrentTemperature)
429
+ .onGet(async () => {
430
+ const value = this.accessory.roomTemperature;
431
+ return value;
432
+ });
433
+ this.melCloudService.getCharacteristic(Characteristic.TargetTemperature)
434
+ .setProps({
435
+ minValue: this.accessory.minTempHeat,
436
+ maxValue: this.accessory.maxTempHeat,
437
+ minStep: this.accessory.temperatureIncrement
438
+ })
439
+ .onGet(async () => {
440
+ const value = this.accessory.setTemperature;
441
+ return value;
442
+ })
443
+ .onSet(async (value) => {
444
+ try {
445
+ deviceData.Device.SetTemperature = value;
446
+ deviceData.Device.EffectiveFlags = Ventilation.EffectiveFlags.SetTemperature;
447
+ await this.melCloudErv.send(deviceData, this.displayMode);
448
+ const info = this.disableLogInfo ? false : this.emit('message', `Set temperature: ${value}${this.accessory.temperatureUnit}`);
449
+ } catch (error) {
450
+ this.emit('warn', `Set temperature error: ${error}`);
451
+ };
452
+ });
453
+ this.melCloudService.getCharacteristic(Characteristic.TemperatureDisplayUnits)
454
+ .onGet(async () => {
455
+ const value = this.accessory.useFahrenheit;
456
+ return value;
457
+ })
458
+ .onSet(async (value) => {
459
+ try {
460
+ accountInfo.UseFahrenheit = [false, true][value];
461
+ await this.melCloud.send(accountInfo);
462
+ this.accessory.useFahrenheit = value;
463
+ const info = this.disableLogInfo ? false : this.emit('message', `Set temperature display unit: ${TemperatureDisplayUnits[value]}`);
464
+ } catch (error) {
465
+ this.emit('warn', `Set temperature display unit error: ${error}`);
466
+ };
467
+ });
468
+ accessory.addService(this.melCloudService);
469
+ break;
470
+ };
471
+
472
+ //temperature sensor service room
473
+ if (this.temperatureSensor && hasRoomTemperature && this.accessory.roomTemperature !== null) {
474
+ const debug = this.enableDebugMode ? this.emit('debug', `Prepare room temperature sensor service`) : false;
475
+ this.roomTemperatureSensorService = new Service.TemperatureSensor(`${serviceName} Room`, `Room Temperature Sensor ${deviceId}`);
476
+ this.roomTemperatureSensorService.addOptionalCharacteristic(Characteristic.ConfiguredName);
477
+ this.roomTemperatureSensorService.setCharacteristic(Characteristic.ConfiguredName, `${serviceName} Room`);
478
+ this.roomTemperatureSensorService.getCharacteristic(Characteristic.CurrentTemperature)
479
+ .setProps({
480
+ minValue: -35,
481
+ maxValue: 150,
482
+ minStep: 0.5
483
+ })
484
+ .onGet(async () => {
485
+ const state = this.accessory.roomTemperature;
486
+ return state;
487
+ })
488
+ accessory.addService(this.roomTemperatureSensorService);
489
+ };
490
+
491
+ //temperature sensor service supply
492
+ if (this.temperatureSensorSupply && hasSupplyTemperature && this.accessory.supplyTemperature !== null) {
493
+ const debug = this.enableDebugMode ? this.emit('debug', `Prepare supply temperature sensor service`) : false;
494
+ this.supplyTemperatureSensorService = new Service.TemperatureSensor(`${serviceName} Supply`, `Supply Temperature Sensor ${deviceId}`);
495
+ this.supplyTemperatureSensorService.addOptionalCharacteristic(Characteristic.ConfiguredName);
496
+ this.supplyTemperatureSensorService.setCharacteristic(Characteristic.ConfiguredName, `${serviceName} Supply`);
497
+ this.supplyTemperatureSensorService.getCharacteristic(Characteristic.CurrentTemperature)
498
+ .setProps({
499
+ minValue: -35,
500
+ maxValue: 150,
501
+ minStep: 0.5
502
+ })
503
+ .onGet(async () => {
504
+ const state = this.accessory.supplyTemperature;
505
+ return state;
506
+ })
507
+ accessory.addService(this.supplyTemperatureSensorService);
508
+ };
509
+
510
+ //temperature sensor service outdoor
511
+ if (this.temperatureSensorOutdoor && hasOutdoorTemperature && this.accessory.outdoorTemperature !== null) {
512
+ const debug = this.enableDebugMode ? this.emit('debug', `Prepare outdoor temperature sensor service`) : false;
513
+ this.outdoorTemperatureSensorService = new Service.TemperatureSensor(`${serviceName} Outdoor`, `Outdoor Temperature Sensor ${deviceId}`);
514
+ this.outdoorTemperatureSensorService.addOptionalCharacteristic(Characteristic.ConfiguredName);
515
+ this.outdoorTemperatureSensorService.setCharacteristic(Characteristic.ConfiguredName, `${serviceName} Outdoor`);
516
+ this.outdoorTemperatureSensorService.getCharacteristic(Characteristic.CurrentTemperature)
517
+ .setProps({
518
+ minValue: -35,
519
+ maxValue: 150,
520
+ minStep: 0.5
521
+ })
522
+ .onGet(async () => {
523
+ const state = this.accessory.outdoorTemperature;
524
+ return state;
525
+ })
526
+ accessory.addService(this.outdoorTemperatureSensorService);
527
+ };
528
+
529
+ //core maintenance
530
+ this.coreMaintenanceService = new Service.FilterMaintenance(`${serviceName} Core Maintenance`, `CoreMaintenance ${deviceId}`);
531
+ this.coreMaintenanceService.addOptionalCharacteristic(Characteristic.ConfiguredName);
532
+ this.coreMaintenanceService.setCharacteristic(Characteristic.ConfiguredName, `${serviceName} Core Maintenance`);
533
+ this.coreMaintenanceService.getCharacteristic(Characteristic.FilterChangeIndication)
534
+ .onGet(async () => {
535
+ const value = this.accessory.coreMaintenanceRequired;
536
+ return value;
537
+ });
538
+ this.coreMaintenanceService.getCharacteristic(Characteristic.ResetFilterIndication)
539
+ .onSet(async (state) => {
540
+ });
541
+ accessory.addService(this.coreMaintenanceService);
542
+
543
+ //filter maintenance
544
+ this.filterMaintenanceService = new Service.FilterMaintenance(`${serviceName} Filter Maintenance`, `FilterMaintenance ${deviceId}`);
545
+ this.filterMaintenanceService.addOptionalCharacteristic(Characteristic.ConfiguredName);
546
+ this.filterMaintenanceService.setCharacteristic(Characteristic.ConfiguredName, `${serviceName} Filter Maintenance`);
547
+ this.filterMaintenanceService.getCharacteristic(Characteristic.FilterChangeIndication)
548
+ .onGet(async () => {
549
+ const value = this.accessory.filterMaintenanceRequired;
550
+ return value;
551
+ });
552
+ this.filterMaintenanceService.getCharacteristic(Characteristic.ResetFilterIndication)
553
+ .onSet(async (state) => {
554
+ });
555
+ accessory.addService(this.filterMaintenanceService);
556
+
557
+ //room CO2 sensor
558
+ if (hasCO2Sensor) {
559
+ this.carbonDioxideSensorService = new Service.CarbonDioxideSensor(`${serviceName} CO2 Sensor`, `CO2Sensor ${deviceId}`);
560
+ this.carbonDioxideSensorService.addOptionalCharacteristic(Characteristic.ConfiguredName);
561
+ this.carbonDioxideSensorService.setCharacteristic(Characteristic.ConfiguredName, `${serviceName} CO2 Sensor`);
562
+ this.carbonDioxideSensorService.getCharacteristic(Characteristic.CarbonDioxideDetected)
563
+ .onGet(async () => {
564
+ const value = this.accessory.roomCO2Detected;
565
+ return value;
566
+ });
567
+ this.carbonDioxideSensorService.getCharacteristic(Characteristic.CarbonDioxideLevel)
568
+ .onGet(async () => {
569
+ const value = this.accessory.roomCO2Level;
570
+ return value;
571
+ });
572
+ accessory.addService(this.carbonDioxideSensorService);
573
+ }
574
+
575
+ //room PM2.5 sensor
576
+ if (hasPM25Sensor) {
577
+ this.airQualitySensorService = new Service.AirQualitySensor(`${serviceName} PM2.5 Sensor`, `PM25Sensor ${deviceId}`);
578
+ this.airQualitySensorService.addOptionalCharacteristic(Characteristic.ConfiguredName);
579
+ this.airQualitySensorService.setCharacteristic(Characteristic.ConfiguredName, `${serviceName} PM2.5 Sensor`);
580
+ this.airQualitySensorService.getCharacteristic(Characteristic.AirQuality)
581
+ .onGet(async () => {
582
+ const value = this.accessory.pM25AirQuality;
583
+ return value;
584
+ });
585
+ this.airQualitySensorService.getCharacteristic(Characteristic.PM2_5Density)
586
+ .onGet(async () => {
587
+ const value = this.accessory.pM25Level;
588
+ return value;
589
+ });
590
+ accessory.addService(this.airQualitySensorService);
591
+ }
592
+
593
+ //presets services
594
+ if (this.presetsConfiguredCount > 0) {
595
+ const debug = this.enableDebugMode ? this.emit('debug', `Prepare presets services`) : false;
596
+ this.presetsServices = [];
597
+
598
+ for (let i = 0; i < this.presetsConfiguredCount; i++) {
599
+ const preset = this.presetsConfigured[i];
600
+ const presetData = presetsOnServer.find(p => p.ID === preset.Id);
601
+
602
+ //get preset name
603
+ const presetName = preset.name;
604
+
605
+ //get preset name prefix
606
+ const presetNamePrefix = preset.namePrefix;
607
+
608
+ const serviceName = presetNamePrefix ? `${accessoryName} ${presetName}` : presetName;
609
+ const serviceType = preset.serviceType;
610
+ const characteristicType = preset.characteristicType;
611
+ const presetService = new serviceType(serviceName, `Preset ${deviceId} ${i}`);
612
+ presetService.addOptionalCharacteristic(Characteristic.ConfiguredName);
613
+ presetService.setCharacteristic(Characteristic.ConfiguredName, serviceName);
614
+ presetService.getCharacteristic(characteristicType)
615
+ .onGet(async () => {
616
+ const state = preset.state;
617
+ return state;
859
618
  })
860
- .onSet(async (value) => {
619
+ .onSet(async (state) => {
861
620
  try {
862
- accountInfo.UseFahrenheit = [false, true][value];
863
- await this.melCloud.send(accountInfo);
864
- this.accessory.useFahrenheit = value;
865
- const info = this.disableLogInfo ? false : this.emit('message', `Set temperature display unit: ${TemperatureDisplayUnits[value]}`);
621
+ switch (state) {
622
+ case true:
623
+ preset.previousSettings = deviceData.Device;
624
+ deviceData.Device.SetTemperature = presetData.SetTemperature;
625
+ deviceData.Device.Power = presetData.Power;
626
+ deviceData.Device.OperationMode = presetData.OperationMode;
627
+ deviceData.Device.VentilationMode = presetData.VentilationMode;
628
+ deviceData.Device.SetFanSpeed = presetData.FanSpeed;
629
+ deviceData.Device.EffectiveFlags = Ventilation.EffectiveFlags.Power;
630
+ break;
631
+ case false:
632
+ deviceData.Device.SetTemperature = preset.previousSettings.SetTemperature;
633
+ deviceData.Device.Power = preset.previousSettings.Power;
634
+ deviceData.Device.OperationMode = preset.previousSettings.OperationMode;
635
+ deviceData.Device.VentilationMode = preset.previousSettings.VentilationMode;
636
+ deviceData.Device.SetFanSpeed = preset.previousSettings.FanSpeed;
637
+ deviceData.Device.EffectiveFlags = Ventilation.EffectiveFlags.Power;
638
+ break;
639
+ };
640
+
641
+ await this.melCloudErv.send(deviceData, this.displayMode);
642
+ const info = this.disableLogInfo ? false : this.emit('message', `${state ? 'Set:' : 'Unset:'} ${presetName}`);
866
643
  } catch (error) {
867
- this.emit('warn', `Set temperature display unit error: ${error}`);
644
+ this.emit('warn', `Set preset error: ${error}`);
868
645
  };
869
646
  });
870
- accessory.addService(this.melCloudService);
871
- break;
872
- case 2: //Thermostat
873
- const debug1 = this.enableDebugMode ? this.emit('debug', `Prepare thermostat service`) : false;
874
- this.melCloudService = new Service.Thermostat(serviceName, `Thermostat ${deviceId}`);
875
- this.melCloudService.getCharacteristic(Characteristic.CurrentHeatingCoolingState)
876
- .onGet(async () => {
877
- const value = this.accessory.currentOperationMode;
878
- return value;
879
- });
880
- this.melCloudService.getCharacteristic(Characteristic.TargetHeatingCoolingState)
881
- .setProps({
882
- minValue: this.accessory.operationModeSetPropsMinValue,
883
- maxValue: this.accessory.operationModeSetPropsMaxValue,
884
- validValues: this.accessory.operationModeSetPropsValidValues
885
- })
647
+ };
648
+ this.presetsServices.push(presetService);
649
+ accessory.addService(presetService);
650
+ };
651
+
652
+ //buttons services
653
+ if (this.buttonsConfiguredCount > 0) {
654
+ const debug = this.enableDebugMode ? this.emit('debug', `Prepare buttons services`) : false;
655
+ this.buttonsServices = [];
656
+
657
+ for (let i = 0; i < this.buttonsConfiguredCount; i++) {
658
+ const button = this.buttonsConfigured[i];
659
+
660
+ //get button mode
661
+ const mode = button.mode;
662
+
663
+ //get button name
664
+ const buttonName = button.name;
665
+
666
+ //get button name prefix
667
+ const buttonNamePrefix = button.namePrefix;
668
+
669
+ const serviceName = buttonNamePrefix ? `${accessoryName} ${buttonName}` : buttonName;
670
+ const serviceType = button.serviceType;
671
+ const characteristicType = button.characteristicType;
672
+ const buttonService = new serviceType(serviceName, `Button ${deviceId} ${i}`);
673
+ buttonService.addOptionalCharacteristic(Characteristic.ConfiguredName);
674
+ buttonService.setCharacteristic(Characteristic.ConfiguredName, serviceName);
675
+ buttonService.getCharacteristic(characteristicType)
886
676
  .onGet(async () => {
887
- const value = this.accessory.targetOperationMode ?? 0; //LOSSNAY, BYPASS, AUTO
888
- return value;
677
+ const state = button.state;
678
+ return state;
889
679
  })
890
- .onSet(async (value) => {
680
+ .onSet(async (state) => {
891
681
  try {
892
- switch (value) {
893
- case 0: //OFF - POWER OFF
894
- deviceData.Device.Power = false;
682
+ switch (mode) {
683
+ case 0: //POWER ON,OFF
684
+ deviceData.Device.Power = state;
895
685
  deviceData.Device.EffectiveFlags = Ventilation.EffectiveFlags.Power;
896
686
  break;
897
- case 1: //HEAT - LOSSNAY
687
+ case 1: //OPERATING MODE RECOVERY
688
+ button.previousValue = state ? deviceData.Device.VentilationMode : button.previousValue ?? deviceData.Device.VentilationMode;
898
689
  deviceData.Device.Power = true;
899
- deviceData.Device.VentilationMode = 0;
690
+ deviceData.Device.VentilationMode = state ? 0 : button.previousValue;
900
691
  deviceData.Device.EffectiveFlags = Ventilation.EffectiveFlags.Power + Ventilation.EffectiveFlags.VentilationMode;
901
692
  break;
902
- case 2: //COOL - BYPASS
693
+ case 2: //OPERATING MODE BYPASS
694
+ button.previousValue = state ? deviceData.Device.VentilationMode : button.previousValue ?? deviceData.Device.VentilationMode;
903
695
  deviceData.Device.Power = true;
904
- deviceData.Device.VentilationMode = hasBypassVentilationMode ? 1 : 0;
696
+ deviceData.Device.VentilationMode = state ? 1 : button.previousValue;
905
697
  deviceData.Device.EffectiveFlags = Ventilation.EffectiveFlags.Power + Ventilation.EffectiveFlags.VentilationMode;
906
- break;
907
- case 3: //AUTO - AUTO
698
+ break
699
+ case 3: //OPERATING MODE AUTO
700
+ button.previousValue = state ? deviceData.Device.VentilationMode : button.previousValue ?? deviceData.Device.VentilationMode;
908
701
  deviceData.Device.Power = true;
909
- deviceData.Device.VentilationMode = hasAutoVentilationMode ? 2 : 0;
702
+ deviceData.Device.VentilationMode = state ? 2 : button.previousValue;
910
703
  deviceData.Device.EffectiveFlags = Ventilation.EffectiveFlags.Power + Ventilation.EffectiveFlags.VentilationMode;
911
704
  break;
912
- };
913
-
914
- await this.melCloudErv.send(deviceData, this.displayMode);
915
- const operationModeText = Ventilation.VentilationMode[deviceData.Device.VentilationMode];
916
- const info = this.disableLogInfo ? false : this.emit('message', `Set operation mode: ${operationModeText}`);
917
- } catch (error) {
918
- this.emit('warn', `Set operation mode error: ${error}`);
919
- };
920
- });
921
- this.melCloudService.getCharacteristic(Characteristic.CurrentTemperature)
922
- .onGet(async () => {
923
- const value = this.accessory.roomTemperature;
924
- return value;
925
- });
926
- this.melCloudService.getCharacteristic(Characteristic.TargetTemperature)
927
- .setProps({
928
- minValue: this.accessory.minTempHeat,
929
- maxValue: this.accessory.maxTempHeat,
930
- minStep: this.accessory.temperatureIncrement
931
- })
932
- .onGet(async () => {
933
- const value = this.accessory.setTemperature;
934
- return value;
935
- })
936
- .onSet(async (value) => {
937
- try {
938
- deviceData.Device.SetTemperature = value;
939
- deviceData.Device.EffectiveFlags = Ventilation.EffectiveFlags.SetTemperature;
940
- await this.melCloudErv.send(deviceData, this.displayMode);
941
- const info = this.disableLogInfo ? false : this.emit('message', `Set temperature: ${value}${this.accessory.temperatureUnit}`);
942
- } catch (error) {
943
- this.emit('warn', `Set temperature error: ${error}`);
944
- };
945
- });
946
- this.melCloudService.getCharacteristic(Characteristic.TemperatureDisplayUnits)
947
- .onGet(async () => {
948
- const value = this.accessory.useFahrenheit;
949
- return value;
950
- })
951
- .onSet(async (value) => {
952
- try {
953
- accountInfo.UseFahrenheit = [false, true][value];
954
- await this.melCloud.send(accountInfo);
955
- this.accessory.useFahrenheit = value;
956
- const info = this.disableLogInfo ? false : this.emit('message', `Set temperature display unit: ${TemperatureDisplayUnits[value]}`);
705
+ case 4: //NIGHT PURGE MODE
706
+ deviceData.Device.Power = true;
707
+ deviceData.Device.NightPurgeMode = state;
708
+ deviceData.Device.EffectiveFlags = Ventilation.EffectiveFlags.Power
709
+ break;
710
+ case 10: //FAN SPEED MODE AUTO
711
+ button.previousValue = state ? deviceData.Device.SetFanSpeed : button.previousValue ?? deviceData.Device.SetFanSpeed;
712
+ deviceData.Device.Power = true;
713
+ deviceData.Device.SetFanSpeed = state ? 0 : button.previousValue;
714
+ deviceData.Device.EffectiveFlags = Ventilation.EffectiveFlags.Power + Ventilation.EffectiveFlags.SetFanSpeed;
715
+ break;
716
+ case 11: //FAN SPEED MODE 1
717
+ button.previousValue = state ? deviceData.Device.SetFanSpeed : button.previousValue ?? deviceData.Device.SetFanSpeed;
718
+ deviceData.Device.Power = true;
719
+ deviceData.Device.SetFanSpeed = state ? 1 : button.previousValue;
720
+ deviceData.Device.EffectiveFlags = Ventilation.EffectiveFlags.Power + Ventilation.EffectiveFlags.SetFanSpeed;
721
+ break;
722
+ case 12: //FAN SPEED MODE 2
723
+ button.previousValue = state ? deviceData.Device.SetFanSpeed : button.previousValue ?? deviceData.Device.SetFanSpeed;
724
+ deviceData.Device.Power = true;
725
+ deviceData.Device.SetFanSpeed = state ? 2 : button.previousValue;
726
+ deviceData.Device.EffectiveFlags = Ventilation.EffectiveFlags.Power + Ventilation.EffectiveFlags.SetFanSpeed;
727
+ break;
728
+ case 13: //FAN SPEED MODE 3
729
+ button.previousValue = state ? deviceData.Device.SetFanSpeed : button.previousValue ?? deviceData.Device.SetFanSpeed;
730
+ deviceData.Device.Power = true;
731
+ deviceData.Device.SetFanSpeed = state ? 3 : button.previousValue;
732
+ deviceData.Device.EffectiveFlags = Ventilation.EffectiveFlags.Power + Ventilation.EffectiveFlags.SetFanSpeed;
733
+ break;
734
+ case 14: //FAN MODE 4
735
+ button.previousValue = state ? deviceData.Device.SetFanSpeed : button.previousValue ?? deviceData.Device.SetFanSpeed;
736
+ deviceData.Device.Power = true;
737
+ deviceData.Device.SetFanSpeed = state ? 4 : button.previousValue;
738
+ deviceData.Device.EffectiveFlags = Ventilation.EffectiveFlags.Power + Ventilation.EffectiveFlags.SetFanSpeed;
739
+ break;
740
+ case 15: //PHYSICAL LOCK CONTROLS
741
+ deviceData.Device = deviceData.Device;
742
+ deviceData.Device.EffectiveFlags = Ventilation.EffectiveFlags.Prohibit;
743
+ break;
744
+ case 16: //ROOM TEMP HIDE
745
+ deviceData.HideRoomTemperature = state;
746
+ break;
747
+ case 17: //SUPPLY TEMP HIDE
748
+ deviceData.HideSupplyTemperature = state;
749
+ break;
750
+ case 18: //OUTDOOR EMP HIDE
751
+ deviceData.hideOutdoorTemperature = state;
752
+ break;
753
+ default:
754
+ this.emit('message', `Unknown button mode: ${mode}`);
755
+ break;
756
+ };
757
+
758
+ await this.melCloudErv.send(deviceData, this.displayMode);
759
+ const info = this.disableLogInfo ? false : this.emit('message', `${state ? `Set: ${buttonName}` : `Unset: ${buttonName}, Set: ${button.previousValue}`}`);
957
760
  } catch (error) {
958
- this.emit('warn', `Set temperature display unit error: ${error}`);
761
+ this.emit('warn', `Set button error: ${error}`);
959
762
  };
960
763
  });
961
- accessory.addService(this.melCloudService);
962
- break;
764
+ this.buttonsServices.push(buttonService);
765
+ accessory.addService(buttonService);
766
+ };
963
767
  };
964
768
 
965
- //temperature sensor service room
966
- if (this.temperatureSensor && hasRoomTemperature && this.accessory.roomTemperature !== null) {
967
- const debug = this.enableDebugMode ? this.emit('debug', `Prepare room temperature sensor service`) : false;
968
- this.roomTemperatureSensorService = new Service.TemperatureSensor(`${serviceName} Room`, `Room Temperature Sensor ${deviceId}`);
969
- this.roomTemperatureSensorService.addOptionalCharacteristic(Characteristic.ConfiguredName);
970
- this.roomTemperatureSensorService.setCharacteristic(Characteristic.ConfiguredName, `${serviceName} Room`);
971
- this.roomTemperatureSensorService.getCharacteristic(Characteristic.CurrentTemperature)
972
- .setProps({
973
- minValue: -35,
974
- maxValue: 150,
975
- minStep: 0.5
976
- })
977
- .onGet(async () => {
978
- const state = this.accessory.roomTemperature;
979
- return state;
980
- })
981
- accessory.addService(this.roomTemperatureSensorService);
982
- };
769
+ return accessory;
770
+ } catch (error) {
771
+ throw new Error(`Prepare accessory error: ${error.message || error}`);
772
+ };
773
+ };
774
+
775
+ //start
776
+ async start() {
777
+ try {
778
+ //melcloud device
779
+ this.melCloudErv = new MelCloudErv({
780
+ contextKey: this.contextKey,
781
+ devicesFile: this.devicesFile,
782
+ deviceId: this.deviceId,
783
+ debugLog: this.enableDebugMode
784
+ });
785
+
786
+ this.melCloudErv.on('externalIntegrations', (deviceData) => {
787
+ try {
788
+ //RESTFul server
789
+ const restFulEnabled = this.restFul.enable || false;
790
+ if (restFulEnabled) {
791
+ if (!this.restFulConnected) {
792
+ this.restFul1 = new RestFul({
793
+ port: this.deviceId.slice(-4),
794
+ debug: this.restFul.debug || false
795
+ });
796
+
797
+ this.restFul1.on('connected', (message) => {
798
+ this.restFulConnected = true;
799
+ this.emit('success', message);
800
+ })
801
+ .on('set', async (key, value) => {
802
+ try {
803
+ await this.setOverExternalIntegration('RESTFul', deviceData, key, value);
804
+ } catch (error) {
805
+ this.emit('warn', error);
806
+ };
807
+ })
808
+ .on('debug', (debug) => {
809
+ this.emit('debug', debug);
810
+ })
811
+ .on('error', (error) => {
812
+ this.emit('warn', error);
813
+ });
814
+ }
815
+ const restFul0 = this.restFulConnected ? this.restFul1.update('info', deviceData) : false;
816
+ const restFul1 = this.restFulConnected ? this.restFul1.update('state', deviceData.Device) : false;
817
+ }
818
+
819
+ //MQTT client
820
+ const mqttEnabled = this.mqtt.enable || false;
821
+ if (mqttEnabled) {
822
+ if (!this.mqttConnected) {
823
+ this.mqtt1 = new Mqtt({
824
+ host: this.mqtt.host,
825
+ port: this.mqtt.port || 1883,
826
+ clientId: `${this.mqtt.clientId}_${this.deviceId}` || `${this.deviceTypeText}_${this.deviceName}_${this.deviceId}`,
827
+ prefix: `${this.mqtt.prefix}/${this.deviceTypeText}/${this.deviceName}`,
828
+ user: this.mqtt.user,
829
+ passwd: this.mqtt.pass,
830
+ debug: this.mqtt.debug || false
831
+ });
832
+
833
+ this.mqtt1.on('connected', (message) => {
834
+ this.mqttConnected = true;
835
+ this.emit('success', message);
836
+ })
837
+ .on('subscribed', (message) => {
838
+ this.emit('success', message);
839
+ })
840
+ .on('set', async (key, value) => {
841
+ try {
842
+ await this.setOverExternalIntegration('MQTT', deviceData, key, value);
843
+ } catch (error) {
844
+ this.emit('warn', error);
845
+ };
846
+ })
847
+ .on('debug', (debug) => {
848
+ this.emit('debug', debug);
849
+ })
850
+ .on('error', (error) => {
851
+ this.emit('warn', error);
852
+ });
853
+ }
854
+ const mqtt0 = this.mqttConnected ? this.mqtt1.emit('publish', `Info`, deviceData) : false;
855
+ const mqtt1 = this.mqttConnected ? this.mqtt1.emit('publish', `State`, deviceData.Device) : false;
856
+ }
857
+ } catch (error) {
858
+ this.emit('warn', `External integration start error: ${error}.`);
859
+ };
860
+ })
861
+ .on('deviceInfo', (manufacturer, modelIndoor, modelOutdoor, serialNumber, firmwareAppVersion) => {
862
+ if (!this.displayDeviceInfo) {
863
+ return;
864
+ }
865
+
866
+ if (!this.disableLogDeviceInfo) {
867
+ this.emit('devInfo', `---- ${this.deviceTypeText}: ${this.deviceName} ----`);
868
+ this.emit('devInfo', `Account: ${this.accountName}`);
869
+ const indoor = modelIndoor ? this.emit('devInfo', `Indoor: ${modelIndoor}`) : false;
870
+ const outdoor = modelOutdoor ? this.emit('devInfo', `Outdoor: ${modelOutdoor}`) : false;
871
+ this.emit('devInfo', `Serial: ${serialNumber}`);
872
+ this.emit('devInfo', `Firmware: ${firmwareAppVersion}`);
873
+ this.emit('devInfo', `Manufacturer: ${manufacturer}`);
874
+ this.emit('devInfo', '----------------------------------');
875
+ };
876
+
877
+ //accessory info
878
+ this.manufacturer = manufacturer;
879
+ this.model = modelIndoor ? modelIndoor : modelOutdoor ? modelOutdoor : `${this.deviceTypeText} ${this.deviceId}`;
880
+ this.serialNumber = serialNumber;
881
+ this.firmwareRevision = firmwareAppVersion;
882
+ this.displayDeviceInfo = false;
883
+ })
884
+ .on('deviceState', async (deviceData) => {
885
+ //presets
886
+ const presetsOnServer = deviceData.Presets ?? [];
887
+
888
+ //device control
889
+ const hideRoomTemperature = deviceData.HideRoomTemperature;
890
+ const hideSupplyTemperature = deviceData.HideSupplyTemperature;
891
+ const hideOutdoorTemperature = deviceData.HideOutdoorTemperature;
892
+
893
+ //device info
894
+ const hasCoolOperationMode = deviceData.Device.HasCoolOperationMode ?? false;
895
+ const hasHeatOperationMode = deviceData.Device.HasHeatOperationMode ?? false;
896
+ const hasAutoOperationMode = deviceData.Device.HasAutoOperationMode ?? false;
897
+ const hasRoomTemperature = deviceData.Device.HasRoomTemperature ?? false;
898
+ const hasSupplyTemperature = deviceData.Device.HasSupplyTemperature ?? false;
899
+ const hasOutdoorTemperature = deviceData.Device.HasOutdoorTemperature ?? false;
900
+ const hasCO2Sensor = deviceData.Device.HasCO2Sensor ?? false;
901
+ const roomCO2Level = deviceData.Device.RoomCO2Level ?? false;
902
+ const roomCO2Detected = hasCO2Sensor && roomCO2Level > 1000 ? true : false;
903
+ const hasPM25Sensor = deviceData.Device.HasPM25Sensor ?? false;
904
+ const pM25SensorStatus = hasPM25Sensor ? deviceData.Device.PM25SensorStatus : 0;
905
+ const pM25Level = hasPM25Sensor ? deviceData.Device.PM25Level : 0;
906
+ const pM25AirQuality = hasPM25Sensor ? pM25Level <= 13 ? 1 : pM25Level <= 35 ? 2 : pM25Level <= 55 ? 3 : pM25Level <= 75 ? 4 : pM25Level <= 110 ? 5 : 0 : 0;
907
+ const hasAutoVentilationMode = deviceData.Device.HasAutoVentilationMode ?? false;
908
+ const hasBypassVentilationMode = deviceData.Device.HasBypassVentilationMode ?? false;
909
+ const hasAutomaticFanSpeed = deviceData.Device.HasAutomaticFanSpeed ?? false;
910
+ const coreMaintenanceRequired = deviceData.Device.CoreMaintenanceRequired ? 1 : 0;
911
+ const filterMaintenanceRequired = deviceData.Device.FilterMaintenanceRequired ? 1 : 0;
912
+ const actualVentilationMode = deviceData.Device.ActualVentilationMode;
913
+ const numberOfFanSpeeds = deviceData.Device.NumberOfFanSpeeds ?? 0;
914
+ const temperatureIncrement = deviceData.Device.TemperatureIncrement ?? 1;
915
+ const minTempHeat = 10;
916
+ const maxTempHeat = 31;
917
+ const minTempCoolDry = 16;
918
+ const maxTempCoolDry = 31;
919
+
920
+ //device state
921
+ const power = deviceData.Device.Power ?? false;
922
+ const roomTemperature = deviceData.Device.RoomTemperature;
923
+ const supplyTemperature = deviceData.Device.SupplyTemperature;
924
+ const outdoorTemperature = deviceData.Device.OutdoorTemperature;
925
+ const nightPurgeMode = deviceData.Device.NightPurgeMode;
926
+ const setTemperature = deviceData.Device.SetTemperature ?? 20;
927
+ const defaultHeatingSetTemperature = deviceData.Device.DefaultHeatingSetTemperature ?? 20;
928
+ const defaultCoolingSetTemperature = deviceData.Device.DefaultCoolingSetTemperature ?? 23;
929
+ const setFanSpeed = deviceData.Device.SetFanSpeed;
930
+ const operationMode = deviceData.Device.OperationMode;
931
+ const ventilationMode = deviceData.Device.VentilationMode;
932
+
933
+ //accessory
934
+ this.accessory.presets = presetsOnServer;
935
+ this.accessory.hasRoomTemperature = hasRoomTemperature;
936
+ this.accessory.hasSupplyTemperature = hasSupplyTemperature;
937
+ this.accessory.hasOutdoorTemperature = hasOutdoorTemperature;
938
+ this.accessory.hasCoolOperationMode = hasCoolOperationMode;
939
+ this.accessory.hasHeatOperationMode = hasHeatOperationMode;
940
+ this.accessory.hasCO2Sensor = hasCO2Sensor;
941
+ this.accessory.roomCO2Level = roomCO2Level;
942
+ this.accessory.roomCO2Detected = roomCO2Detected;
943
+ this.accessory.hasPM25Sensor = hasPM25Sensor;
944
+ this.accessory.pM25SensorStatus = pM25SensorStatus;
945
+ this.accessory.pM25Level = pM25Level;
946
+ this.accessory.pM25AirQuality = pM25AirQuality;
947
+ this.accessory.hasAutoVentilationMode = hasAutoVentilationMode;
948
+ this.accessory.hasBypassVentilationMode = hasBypassVentilationMode;
949
+ this.accessory.hasAutomaticFanSpeed = hasAutomaticFanSpeed;
950
+ this.accessory.coreMaintenanceRequired = coreMaintenanceRequired;
951
+ this.accessory.filterMaintenanceRequired = filterMaintenanceRequired;
952
+ this.accessory.actualVentilationMode = actualVentilationMode;
953
+ this.accessory.numberOfFanSpeeds = numberOfFanSpeeds;
954
+ this.accessory.power = power ? 1 : 0;
955
+ this.accessory.operationMode = operationMode;
956
+ this.accessory.ventilationMode = ventilationMode;
957
+ this.accessory.roomTemperature = roomTemperature;
958
+ this.accessory.supplyTemperature = supplyTemperature;
959
+ this.accessory.outdoorTemperature = outdoorTemperature;
960
+ this.accessory.setTemperature = setTemperature;
961
+ this.accessory.defaultHeatingSetTemperature = defaultHeatingSetTemperature;
962
+ this.accessory.defaultCoolingSetTemperature = defaultCoolingSetTemperature;
963
+ this.accessory.lockPhysicalControl = 0;
964
+ this.accessory.temperatureIncrement = temperatureIncrement;
965
+ this.accessory.minTempHeat = minTempHeat;
966
+ this.accessory.temperatureIncrement = maxTempHeat;
967
+ this.accessory.minTempCoolDry = minTempCoolDry;
968
+ this.accessory.maxTempCoolDry = maxTempCoolDry;
969
+
970
+ //ventilation mode - 0, HEAT, 2, COOL, 4, 5, 6, FAN, AUTO
971
+ switch (this.displayMode) {
972
+ case 1: //Heater Cooler
973
+ switch (ventilationMode) {
974
+ case 0: //LOSSNAY
975
+ this.accessory.currentOperationMode = 2; //INACTIVE, IDLE, HEATING, COOLIN
976
+ this.accessory.targetOperationMode = 1; //AUTO, HEAT, COOL
977
+ break;
978
+ case 1: //BYPASS
979
+ this.accessory.currentOperationMode = 3;
980
+ this.accessory.targetOperationMode = 2;
981
+ break;
982
+ case 2: //AUTO
983
+ switch (actualVentilationMode) {
984
+ case 0: //LOSSNAY
985
+ this.accessory.currentOperationMode = 2;
986
+ break;
987
+ case 1: //BYPASS
988
+ this.accessory.currentOperationMode = 3;
989
+ break;
990
+ default:
991
+ this.emit('warn', `Unknown actual ventilation mode: ${actualVentilationMode}`);
992
+ break;
993
+ };
994
+ this.accessory.targetOperationMode = 0;
995
+ break;
996
+ default:
997
+ this.emit('warn', `Unknown ventilation mode: ${ventilationMode}`);
998
+ break;
999
+ };
983
1000
 
984
- //temperature sensor service supply
985
- if (this.temperatureSensorSupply && hasSupplyTemperature && this.accessory.supplyTemperature !== null) {
986
- const debug = this.enableDebugMode ? this.emit('debug', `Prepare supply temperature sensor service`) : false;
987
- this.supplyTemperatureSensorService = new Service.TemperatureSensor(`${serviceName} Supply`, `Supply Temperature Sensor ${deviceId}`);
988
- this.supplyTemperatureSensorService.addOptionalCharacteristic(Characteristic.ConfiguredName);
989
- this.supplyTemperatureSensorService.setCharacteristic(Characteristic.ConfiguredName, `${serviceName} Supply`);
990
- this.supplyTemperatureSensorService.getCharacteristic(Characteristic.CurrentTemperature)
991
- .setProps({
992
- minValue: -35,
993
- maxValue: 150,
994
- minStep: 0.5
995
- })
996
- .onGet(async () => {
997
- const state = this.accessory.supplyTemperature;
998
- return state;
999
- })
1000
- accessory.addService(this.supplyTemperatureSensorService);
1001
- };
1001
+ this.accessory.currentOperationMode = !power ? 0 : this.accessory.currentOperationMode;
1002
+ this.accessory.operationModeSetPropsMinValue = hasAutoVentilationMode ? 0 : 1;
1003
+ this.accessory.operationModeSetPropsMaxValue = hasAutoVentilationMode ? 2 : 2;
1004
+ this.accessory.operationModeSetPropsValidValues = hasAutoVentilationMode ? (hasBypassVentilationMode ? [0, 1, 2] : [0, 2]) : (hasBypassVentilationMode ? [1, 2] : [2]);
1002
1005
 
1003
- //temperature sensor service outdoor
1004
- if (this.temperatureSensorOutdoor && hasOutdoorTemperature && this.accessory.outdoorTemperature !== null) {
1005
- const debug = this.enableDebugMode ? this.emit('debug', `Prepare outdoor temperature sensor service`) : false;
1006
- this.outdoorTemperatureSensorService = new Service.TemperatureSensor(`${serviceName} Outdoor`, `Outdoor Temperature Sensor ${deviceId}`);
1007
- this.outdoorTemperatureSensorService.addOptionalCharacteristic(Characteristic.ConfiguredName);
1008
- this.outdoorTemperatureSensorService.setCharacteristic(Characteristic.ConfiguredName, `${serviceName} Outdoor`);
1009
- this.outdoorTemperatureSensorService.getCharacteristic(Characteristic.CurrentTemperature)
1010
- .setProps({
1011
- minValue: -35,
1012
- maxValue: 150,
1013
- minStep: 0.5
1014
- })
1015
- .onGet(async () => {
1016
- const state = this.accessory.outdoorTemperature;
1017
- return state;
1018
- })
1019
- accessory.addService(this.outdoorTemperatureSensorService);
1020
- };
1006
+ //fan speed mode
1007
+ this.accessory.fanSpeedSetPropsMaxValue = 2;
1008
+ switch (numberOfFanSpeeds) {
1009
+ case 2: //Fan speed mode 2
1010
+ this.accessory.fanSpeed = hasAutomaticFanSpeed ? [3, 1, 2][setFanSpeed] : [0, 1, 2][setFanSpeed];
1011
+ this.accessory.fanSpeedSetPropsMaxValue = hasAutomaticFanSpeed ? 3 : 2;
1012
+ break;
1013
+ case 3: //Fan speed mode 3
1014
+ this.this.accessory.fanSpeed = hasAutomaticFanSpeed ? [4, 1, 2, 3][setFanSpeed] : [0, 1, 2, 3][setFanSpeed];
1015
+ this.accessory.fanSpeedSetPropsMaxValue = hasAutomaticFanSpeed ? 4 : 3;
1016
+ break;
1017
+ case 4: //Fan speed mode 4
1018
+ this.accessory.fanSpeed = hasAutomaticFanSpeed ? [5, 1, 2, 3, 4][setFanSpeed] : [0, 1, 2, 3, 4][setFanSpeed];
1019
+ this.accessory.fanSpeedSetPropsMaxValue = hasAutomaticFanSpeed ? 5 : 4;
1020
+ break;
1021
+ };
1021
1022
 
1022
- //core maintenance
1023
- this.coreMaintenanceService = new Service.FilterMaintenance(`${serviceName} Core Maintenance`, `CoreMaintenance ${deviceId}`);
1024
- this.coreMaintenanceService.addOptionalCharacteristic(Characteristic.ConfiguredName);
1025
- this.coreMaintenanceService.setCharacteristic(Characteristic.ConfiguredName, `${serviceName} Core Maintenance`);
1026
- this.coreMaintenanceService.getCharacteristic(Characteristic.FilterChangeIndication)
1027
- .onGet(async () => {
1028
- const value = this.accessory.coreMaintenanceRequired;
1029
- return value;
1030
- });
1031
- this.coreMaintenanceService.getCharacteristic(Characteristic.ResetFilterIndication)
1032
- .onSet(async (state) => {
1033
- });
1034
- accessory.addService(this.coreMaintenanceService);
1023
+ //update characteristics
1024
+ if (this.melCloudService) {
1025
+ this.melCloudService
1026
+ .updateCharacteristic(Characteristic.Active, power)
1027
+ .updateCharacteristic(Characteristic.CurrentHeaterCoolerState, this.accessory.currentOperationMode)
1028
+ .updateCharacteristic(Characteristic.TargetHeaterCoolerState, this.accessory.targetOperationMode)
1029
+ .updateCharacteristic(Characteristic.CurrentTemperature, roomTemperature)
1030
+ .updateCharacteristic(Characteristic.RotationSpeed, this.accessory.fanSpeed)
1031
+ .updateCharacteristic(Characteristic.LockPhysicalControls, this.accessory.lockPhysicalControl)
1032
+ .updateCharacteristic(Characteristic.TemperatureDisplayUnits, this.accessory.useFahrenheit);
1033
+ const updateDefCool = hasCoolOperationMode ? this.melCloudService.updateCharacteristic(Characteristic.CoolingThresholdTemperature, defaultCoolingSetTemperature) : false;
1034
+ const updateDefHeat = hasHeatOperationMode ? this.melCloudService.updateCharacteristic(Characteristic.HeatingThresholdTemperature, defaultHeatingSetTemperature) : false;
1035
+ };
1036
+ break;
1037
+ case 2: //Thermostat
1038
+ //operation mode - 0, HEAT, 2, COOL, 4, 5, 6, FAN, AUTO
1039
+ switch (ventilationMode) {
1040
+ case 0: //LOSSNAY
1041
+ this.accessory.currentOperationMode = 1; //OFF, HEAT, COOL
1042
+ this.accessory.targetOperationMode = 1; //OFF, HEAT, COOL, AUTO
1043
+ break;
1044
+ case 1: //BYPASS
1045
+ this.accessory.currentOperationMode = 2;
1046
+ this.accessory.targetOperationMode = 2;
1047
+ break;
1048
+ case 2: //AUTO
1049
+ switch (actualVentilationMode) {
1050
+ case 0: //LOSSNAY
1051
+ this.accessory.currentOperationMode = 1;
1052
+ break;
1053
+ case 1: //BYPASS
1054
+ this.accessory.currentOperationMode = 2;
1055
+ break;
1056
+ default:
1057
+ this.emit('warn', `Unknown actual ventilation mode: ${actualVentilationMode}`);
1058
+ break;
1059
+ };
1060
+ this.accessory.targetOperationMode = 3;
1061
+ break;
1062
+ default:
1063
+ this.emit('warn', `Unknown ventilation mode: ${ventilationMode}`);
1064
+ break;
1065
+ };
1035
1066
 
1036
- //filter maintenance
1037
- this.filterMaintenanceService = new Service.FilterMaintenance(`${serviceName} Filter Maintenance`, `FilterMaintenance ${deviceId}`);
1038
- this.filterMaintenanceService.addOptionalCharacteristic(Characteristic.ConfiguredName);
1039
- this.filterMaintenanceService.setCharacteristic(Characteristic.ConfiguredName, `${serviceName} Filter Maintenance`);
1040
- this.filterMaintenanceService.getCharacteristic(Characteristic.FilterChangeIndication)
1041
- .onGet(async () => {
1042
- const value = this.accessory.filterMaintenanceRequired;
1043
- return value;
1044
- });
1045
- this.filterMaintenanceService.getCharacteristic(Characteristic.ResetFilterIndication)
1046
- .onSet(async (state) => {
1047
- });
1048
- accessory.addService(this.filterMaintenanceService);
1067
+ this.accessory.currentOperationMode = !power ? 0 : this.accessory.currentOperationMode;
1068
+ this.accessory.targetOperationMode = !power ? 0 : this.accessory.targetOperationMode;
1069
+ this.accessory.operationModeSetPropsMinValue = hasAutoVentilationMode ? 0 : 0;
1070
+ this.accessory.operationModeSetPropsMaxValue = hasAutoVentilationMode ? 3 : 2;
1071
+ this.accessory.operationModeSetPropsValidValues = hasAutoVentilationMode ? (hasBypassVentilationMode ? [0, 1, 2, 3] : [0, 2, 3]) : (hasBypassVentilationMode ? [0, 1, 2] : [0, 2]);
1049
1072
 
1050
- //room CO2 sensor
1051
- if (hasCO2Sensor) {
1052
- this.carbonDioxideSensorService = new Service.CarbonDioxideSensor(`${serviceName} CO2 Sensor`, `CO2Sensor ${deviceId}`);
1053
- this.carbonDioxideSensorService.addOptionalCharacteristic(Characteristic.ConfiguredName);
1054
- this.carbonDioxideSensorService.setCharacteristic(Characteristic.ConfiguredName, `${serviceName} CO2 Sensor`);
1055
- this.carbonDioxideSensorService.getCharacteristic(Characteristic.CarbonDioxideDetected)
1056
- .onGet(async () => {
1057
- const value = this.accessory.roomCO2Detected;
1058
- return value;
1059
- });
1060
- this.carbonDioxideSensorService.getCharacteristic(Characteristic.CarbonDioxideLevel)
1061
- .onGet(async () => {
1062
- const value = this.accessory.roomCO2Level;
1063
- return value;
1064
- });
1065
- accessory.addService(this.carbonDioxideSensorService);
1066
- }
1073
+ //update characteristics
1074
+ if (this.melCloudService) {
1075
+ this.melCloudService
1076
+ .updateCharacteristic(Characteristic.CurrentHeatingCoolingState, this.accessory.currentOperationMode)
1077
+ .updateCharacteristic(Characteristic.TargetHeatingCoolingState, this.accessory.targetOperationMode)
1078
+ .updateCharacteristic(Characteristic.CurrentTemperature, roomTemperature)
1079
+ .updateCharacteristic(Characteristic.TargetTemperature, setTemperature)
1080
+ .updateCharacteristic(Characteristic.TemperatureDisplayUnits, this.accessory.useFahrenheit);
1081
+ };
1082
+ break;
1083
+ };
1067
1084
 
1068
- //room PM2.5 sensor
1069
- if (hasPM25Sensor) {
1070
- this.airQualitySensorService = new Service.AirQualitySensor(`${serviceName} PM2.5 Sensor`, `PM25Sensor ${deviceId}`);
1071
- this.airQualitySensorService.addOptionalCharacteristic(Characteristic.ConfiguredName);
1072
- this.airQualitySensorService.setCharacteristic(Characteristic.ConfiguredName, `${serviceName} PM2.5 Sensor`);
1073
- this.airQualitySensorService.getCharacteristic(Characteristic.AirQuality)
1074
- .onGet(async () => {
1075
- const value = this.accessory.pM25AirQuality;
1076
- return value;
1077
- });
1078
- this.airQualitySensorService.getCharacteristic(Characteristic.PM2_5Density)
1079
- .onGet(async () => {
1080
- const value = this.accessory.pM25Level;
1081
- return value;
1082
- });
1083
- accessory.addService(this.airQualitySensorService);
1084
- }
1085
+ //update temperature sensors
1086
+ if (this.roomTemperatureSensorService) {
1087
+ this.roomTemperatureSensorService
1088
+ .updateCharacteristic(Characteristic.CurrentTemperature, roomTemperature)
1089
+ };
1085
1090
 
1086
- //presets services
1087
- if (this.presetsConfiguredCount > 0) {
1088
- const debug = this.enableDebugMode ? this.emit('debug', `Prepare presets services`) : false;
1089
- this.presetsServices = [];
1091
+ if (this.outdoorTemperatureSensorService) {
1092
+ this.outdoorTemperatureSensorService
1093
+ .updateCharacteristic(Characteristic.CurrentTemperature, outdoorTemperature)
1094
+ };
1090
1095
 
1091
- for (let i = 0; i < this.presetsConfiguredCount; i++) {
1092
- const preset = this.presetsConfigured[i];
1093
- const presetData = presetsOnServer.find(p => p.ID === preset.Id);
1096
+ if (this.supplyTemperatureSensorService) {
1097
+ this.supplyTemperatureSensorService
1098
+ .updateCharacteristic(Characteristic.CurrentTemperature, supplyTemperature)
1099
+ };
1094
1100
 
1095
- //get preset name
1096
- const presetName = preset.name;
1101
+ //update core maintenance
1102
+ if (this.coreMaintenanceService) {
1103
+ this.coreMaintenanceService
1104
+ .updateCharacteristic(Characteristic.FilterChangeIndication, coreMaintenanceRequired)
1105
+ }
1097
1106
 
1098
- //get preset name prefix
1099
- const presetNamePrefix = preset.namePrefix;
1107
+ //update filter maintenance
1108
+ if (this.filterMaintenanceService) {
1109
+ this.filterMaintenanceService
1110
+ .updateCharacteristic(Characteristic.FilterChangeIndication, filterMaintenanceRequired)
1111
+ }
1100
1112
 
1101
- const serviceName = presetNamePrefix ? `${accessoryName} ${presetName}` : presetName;
1102
- const serviceType = preset.serviceType;
1103
- const characteristicType = preset.characteristicType;
1104
- const presetService = new serviceType(serviceName, `Preset ${deviceId} ${i}`);
1105
- presetService.addOptionalCharacteristic(Characteristic.ConfiguredName);
1106
- presetService.setCharacteristic(Characteristic.ConfiguredName, serviceName);
1107
- presetService.getCharacteristic(characteristicType)
1108
- .onGet(async () => {
1109
- const state = preset.state;
1110
- return state;
1111
- })
1112
- .onSet(async (state) => {
1113
- try {
1114
- switch (state) {
1115
- case true:
1116
- preset.previousSettings = deviceData.Device;
1117
- deviceData.Device.SetTemperature = presetData.SetTemperature;
1118
- deviceData.Device.Power = presetData.Power;
1119
- deviceData.Device.OperationMode = presetData.OperationMode;
1120
- deviceData.Device.VentilationMode = presetData.VentilationMode;
1121
- deviceData.Device.SetFanSpeed = presetData.FanSpeed;
1122
- deviceData.Device.EffectiveFlags = Ventilation.EffectiveFlags.Power;
1123
- break;
1124
- case false:
1125
- deviceData.Device.SetTemperature = preset.previousSettings.SetTemperature;
1126
- deviceData.Device.Power = preset.previousSettings.Power;
1127
- deviceData.Device.OperationMode = preset.previousSettings.OperationMode;
1128
- deviceData.Device.VentilationMode = preset.previousSettings.VentilationMode;
1129
- deviceData.Device.SetFanSpeed = preset.previousSettings.FanSpeed;
1130
- deviceData.Device.EffectiveFlags = Ventilation.EffectiveFlags.Power;
1131
- break;
1132
- };
1113
+ //update CO2 sensor
1114
+ if (this.carbonDioxideSensorService) {
1115
+ this.carbonDioxideSensorService
1116
+ .updateCharacteristic(Characteristic.CarbonDioxideDetected, roomCO2Detected)
1117
+ .updateCharacteristic(Characteristic.CarbonDioxideLevel, roomCO2Level)
1118
+ }
1119
+
1120
+ //update PM2.5 sensor
1121
+ if (this.airQualitySensorService) {
1122
+ this.airQualitySensorService
1123
+ .updateCharacteristic(Characteristic.AirQuality, pM25AirQuality)
1124
+ .updateCharacteristic(Characteristic.PM2_5Density, pM25Level)
1125
+ }
1133
1126
 
1134
- await this.melCloudErv.send(deviceData, this.displayMode);
1135
- const info = this.disableLogInfo ? false : this.emit('message', `${state ? 'Set:' : 'Unset:'} ${presetName}`);
1136
- } catch (error) {
1137
- this.emit('warn', `Set preset error: ${error}`);
1127
+ //update presets state
1128
+ if (this.presetsConfigured.length > 0) {
1129
+ for (let i = 0; i < this.presetsConfigured.length; i++) {
1130
+ const preset = this.presetsConfigured[i];
1131
+ const presetData = presetsOnServer.find(p => p.ID === preset.Id);
1132
+
1133
+ preset.state = presetData ? (presetData.Power === power
1134
+ && presetData.SetTemperature === setTemperature
1135
+ && presetData.OperationMode === operationMode
1136
+ && presetData.VentilationMode === ventilationMode
1137
+ && presetData.FanSpeed === setFanSpeed) : false;
1138
+
1139
+ if (this.presetsServices) {
1140
+ const characteristicType = preset.characteristicType;
1141
+ this.presetsServices[i]
1142
+ .updateCharacteristic(characteristicType, preset.state)
1138
1143
  };
1139
- });
1140
- };
1141
- this.presetsServices.push(presetService);
1142
- accessory.addService(presetService);
1143
- };
1144
+ };
1145
+ };
1144
1146
 
1145
- //buttons services
1146
- if (this.buttonsConfiguredCount > 0) {
1147
- const debug = this.enableDebugMode ? this.emit('debug', `Prepare buttons services`) : false;
1148
- this.buttonsServices = [];
1147
+ //update buttons state
1148
+ if (this.buttonsConfiguredCount > 0) {
1149
+ for (let i = 0; i < this.buttonsConfiguredCount; i++) {
1150
+ const button = this.buttonsConfigured[i];
1151
+ const mode = button.mode;;
1152
+ switch (mode) {
1153
+ case 0: //POWER ON,OFF
1154
+ button.state = (power === true);
1155
+ break;
1156
+ case 1: //OPERATION MODE RECOVERY
1157
+ button.state = power ? (ventilationMode === 0) : false;
1158
+ break;
1159
+ case 2: //OPERATION MODE BYPASS
1160
+ button.state = power ? (ventilationMode === 1) : false;
1161
+ break;
1162
+ case 3: //OPERATION MODE AUTO
1163
+ button.state = power ? (ventilationMode === 2) : false;
1164
+ break;
1165
+ case 4: //NIGHT PURGE MODE
1166
+ button.state = power ? (nightPurgeMode === true) : false;
1167
+ break;
1168
+ case 10: //FAN SPEED MODE AUTO
1169
+ button.state = power ? (setFanSpeed === 0) : false;
1170
+ break;
1171
+ case 11: //FAN SPEED MODE 1
1172
+ button.state = power ? (setFanSpeed === 1) : false;
1173
+ break;
1174
+ case 12: //FAN SPEED MODE 2
1175
+ button.state = power ? (setFanSpeed === 2) : false;
1176
+ break;
1177
+ case 13: //FAN SPEED MODE 3
1178
+ button.state = power ? (setFanSpeed === 3) : false;
1179
+ break;
1180
+ case 14: //FAN SPEED MODE 4
1181
+ button.state = power ? (setFanSpeed === 4) : false;
1182
+ break;
1183
+ case 15: //PHYSICAL LOCK CONTROLS
1184
+ button.state = (this.accessory.lockPhysicalControl === 1);
1185
+ break;
1186
+ case 16: //ROOM TEMP HIDE
1187
+ button.state = (hideRoomTemperature === true);
1188
+ break;
1189
+ case 17: //SUPPLY TEMP HIDE
1190
+ button.state = (hideSupplyTemperature === true);
1191
+ break;
1192
+ case 18: //OUTDOOR TEMP HIDE
1193
+ button.state = (hideOutdoorTemperature === true);
1194
+ break;
1195
+ default: //Unknown button
1196
+ this.emit('warn', `Unknown button mode: ${mode} detected.`);
1197
+ break;
1198
+ };
1149
1199
 
1150
- for (let i = 0; i < this.buttonsConfiguredCount; i++) {
1151
- const button = this.buttonsConfigured[i];
1200
+ //update services
1201
+ if (this.buttonsServices) {
1202
+ const characteristicType = button.characteristicType;
1203
+ this.buttonsServices[i]
1204
+ .updateCharacteristic(characteristicType, button.state)
1205
+ };
1206
+ };
1207
+ };
1152
1208
 
1153
- //get button mode
1154
- const mode = button.mode;
1209
+ //log current state
1210
+ if (!this.disableLogInfo) {
1211
+ this.emit('message', `Power: ${power ? 'ON' : 'OFF'}`);
1212
+ this.emit('message', `Target ventilation mode: ${Ventilation.OperationMode[ventilationMode]}`);
1213
+ this.emit('message', `Current ventilation mode: ${Ventilation.OperationMode[actualVentilationMode]}`);
1214
+ this.emit('message', `Target temperature: ${setTemperature}${this.accessory.temperatureUnit}`);
1215
+ this.emit('message', `Room temperature: ${roomTemperature}${this.accessory.temperatureUnit}`);
1216
+ const info1 = hasSupplyTemperature && deviceData.Device.SupplyTemperature !== null ? this.emit('message', `Supply temperature: ${roomTemperature}${this.accessory.temperatureUnit}`) : false;
1217
+ const info2 = hasOutdoorTemperature && deviceData.Device.OutdoorTemperature !== null ? this.emit('message', `Outdoor temperature: ${roomTemperature}${this.accessory.temperatureUnit}`) : false;
1218
+ this.emit('message', `Fan speed mode: ${Ventilation.FanSpeed[setFanSpeed]}`);
1219
+ this.emit('message', `Temperature display unit: ${this.accessory.temperatureUnit}`);
1220
+ this.emit('message', `Core maintenance: ${Ventilation.CoreMaintenance[coreMaintenanceRequired]}`);
1221
+ this.emit('message', `Filter maintenance: ${Ventilation.FilterMaintenance[filterMaintenanceRequired]}`);
1222
+ const info5 = hasCO2Sensor ? this.emit('message', `CO2 detected: ${Ventilation.Co2Detected[roomCO2Detected]}`) : false;
1223
+ const info6 = hasCO2Sensor ? this.emit('message', `CO2 level: ${roomCO2Level} ppm`) : false;
1224
+ const info7 = hasPM25Sensor ? this.emit('message', `PM2.5 air quality: ${Ventilation.PM25AirQuality[pM25AirQuality]}`) : false;
1225
+ const info8 = hasPM25Sensor ? this.emit('message', `PM2.5 level: ${pM25Level} µg/m`) : false;
1226
+ };
1155
1227
 
1156
- //get button name
1157
- const buttonName = button.name;
1228
+ //start prepare accessory
1229
+ if (!this.startPrepareAccessory) {
1230
+ return;
1231
+ }
1158
1232
 
1159
- //get button name prefix
1160
- const buttonNamePrefix = button.namePrefix;
1233
+ try {
1234
+ const accessory = await this.prepareAccessory(this.accountInfo, deviceData, this.deviceId, this.deviceTypeText, this.deviceName, this.accountName);
1235
+ this.emit('publishAccessory', accessory);
1236
+ this.startPrepareAccessory = false;
1237
+ } catch (error) {
1238
+ this.emit('error', error);
1239
+ };
1240
+ })
1241
+ .on('success', (message) => {
1242
+ this.emit('success', message);
1243
+ })
1244
+ .on('message', (message) => {
1245
+ this.emit('message', message);
1246
+ })
1247
+ .on('debug', (debug) => {
1248
+ this.emit('debug', debug);
1249
+ })
1250
+ .on('warn', async (warn) => {
1251
+ this.emit('warn', warn);
1252
+ })
1253
+ .on('error', async (error) => {
1254
+ this.emit('error', error);
1255
+ });
1161
1256
 
1162
- const serviceName = buttonNamePrefix ? `${accessoryName} ${buttonName}` : buttonName;
1163
- const serviceType = button.serviceType;
1164
- const characteristicType = button.characteristicType;
1165
- const buttonService = new serviceType(serviceName, `Button ${deviceId} ${i}`);
1166
- buttonService.addOptionalCharacteristic(Characteristic.ConfiguredName);
1167
- buttonService.setCharacteristic(Characteristic.ConfiguredName, serviceName);
1168
- buttonService.getCharacteristic(characteristicType)
1169
- .onGet(async () => {
1170
- const state = button.state;
1171
- return state;
1172
- })
1173
- .onSet(async (state) => {
1174
- try {
1175
- switch (mode) {
1176
- case 0: //POWER ON,OFF
1177
- deviceData.Device.Power = state;
1178
- deviceData.Device.EffectiveFlags = Ventilation.EffectiveFlags.Power;
1179
- break;
1180
- case 1: //OPERATING MODE RECOVERY
1181
- button.previousValue = state ? deviceData.Device.VentilationMode : button.previousValue ?? deviceData.Device.VentilationMode;
1182
- deviceData.Device.Power = true;
1183
- deviceData.Device.VentilationMode = state ? 0 : button.previousValue;
1184
- deviceData.Device.EffectiveFlags = Ventilation.EffectiveFlags.Power + Ventilation.EffectiveFlags.VentilationMode;
1185
- break;
1186
- case 2: //OPERATING MODE BYPASS
1187
- button.previousValue = state ? deviceData.Device.VentilationMode : button.previousValue ?? deviceData.Device.VentilationMode;
1188
- deviceData.Device.Power = true;
1189
- deviceData.Device.VentilationMode = state ? 1 : button.previousValue;
1190
- deviceData.Device.EffectiveFlags = Ventilation.EffectiveFlags.Power + Ventilation.EffectiveFlags.VentilationMode;
1191
- break
1192
- case 3: //OPERATING MODE AUTO
1193
- button.previousValue = state ? deviceData.Device.VentilationMode : button.previousValue ?? deviceData.Device.VentilationMode;
1194
- deviceData.Device.Power = true;
1195
- deviceData.Device.VentilationMode = state ? 2 : button.previousValue;
1196
- deviceData.Device.EffectiveFlags = Ventilation.EffectiveFlags.Power + Ventilation.EffectiveFlags.VentilationMode;
1197
- break;
1198
- case 4: //NIGHT PURGE MODE
1199
- deviceData.Device.Power = true;
1200
- deviceData.Device.NightPurgeMode = state;
1201
- deviceData.Device.EffectiveFlags = Ventilation.EffectiveFlags.Power
1202
- break;
1203
- case 10: //FAN SPEED MODE AUTO
1204
- button.previousValue = state ? deviceData.Device.SetFanSpeed : button.previousValue ?? deviceData.Device.SetFanSpeed;
1205
- deviceData.Device.Power = true;
1206
- deviceData.Device.SetFanSpeed = state ? 0 : button.previousValue;
1207
- deviceData.Device.EffectiveFlags = Ventilation.EffectiveFlags.Power + Ventilation.EffectiveFlags.SetFanSpeed;
1208
- break;
1209
- case 11: //FAN SPEED MODE 1
1210
- button.previousValue = state ? deviceData.Device.SetFanSpeed : button.previousValue ?? deviceData.Device.SetFanSpeed;
1211
- deviceData.Device.Power = true;
1212
- deviceData.Device.SetFanSpeed = state ? 1 : button.previousValue;
1213
- deviceData.Device.EffectiveFlags = Ventilation.EffectiveFlags.Power + Ventilation.EffectiveFlags.SetFanSpeed;
1214
- break;
1215
- case 12: //FAN SPEED MODE 2
1216
- button.previousValue = state ? deviceData.Device.SetFanSpeed : button.previousValue ?? deviceData.Device.SetFanSpeed;
1217
- deviceData.Device.Power = true;
1218
- deviceData.Device.SetFanSpeed = state ? 2 : button.previousValue;
1219
- deviceData.Device.EffectiveFlags = Ventilation.EffectiveFlags.Power + Ventilation.EffectiveFlags.SetFanSpeed;
1220
- break;
1221
- case 13: //FAN SPEED MODE 3
1222
- button.previousValue = state ? deviceData.Device.SetFanSpeed : button.previousValue ?? deviceData.Device.SetFanSpeed;
1223
- deviceData.Device.Power = true;
1224
- deviceData.Device.SetFanSpeed = state ? 3 : button.previousValue;
1225
- deviceData.Device.EffectiveFlags = Ventilation.EffectiveFlags.Power + Ventilation.EffectiveFlags.SetFanSpeed;
1226
- break;
1227
- case 14: //FAN MODE 4
1228
- button.previousValue = state ? deviceData.Device.SetFanSpeed : button.previousValue ?? deviceData.Device.SetFanSpeed;
1229
- deviceData.Device.Power = true;
1230
- deviceData.Device.SetFanSpeed = state ? 4 : button.previousValue;
1231
- deviceData.Device.EffectiveFlags = Ventilation.EffectiveFlags.Power + Ventilation.EffectiveFlags.SetFanSpeed;
1232
- break;
1233
- case 15: //PHYSICAL LOCK CONTROLS
1234
- deviceData.Device = deviceData.Device;
1235
- deviceData.Device.EffectiveFlags = Ventilation.EffectiveFlags.Prohibit;
1236
- break;
1237
- case 16: //ROOM TEMP HIDE
1238
- deviceData.HideRoomTemperature = state;
1239
- break;
1240
- case 17: //SUPPLY TEMP HIDE
1241
- deviceData.HideSupplyTemperature = state;
1242
- break;
1243
- case 18: //OUTDOOR EMP HIDE
1244
- deviceData.hideOutdoorTemperature = state;
1245
- break;
1246
- default:
1247
- this.emit('message', `Unknown button mode: ${mode}`);
1248
- break;
1249
- };
1257
+ //check state
1258
+ await this.melCloudErv.checkState();
1250
1259
 
1251
- await this.melCloudErv.send(deviceData, this.displayMode);
1252
- const info = this.disableLogInfo ? false : this.emit('message', `${state ? `Set: ${buttonName}` : `Unset: ${buttonName}, Set: ${button.previousValue}`}`);
1253
- } catch (error) {
1254
- this.emit('warn', `Set button error: ${error}`);
1255
- };
1256
- });
1257
- this.buttonsServices.push(buttonService);
1258
- accessory.addService(buttonService);
1259
- };
1260
- };
1260
+ //start impule generator
1261
+ await this.melCloudErv.impulseGenerator.start([{ name: 'checkState', sampling: this.refreshInterval }]);
1261
1262
 
1262
- return accessory;
1263
+ return true;
1263
1264
  } catch (error) {
1264
- throw new Error(`Prepare accessory error: ${error.message || error}`);
1265
+ throw new Error(`Start error: ${error}`);
1265
1266
  };
1266
1267
  };
1267
1268
  };