diff --git a/CHANGELOG.md b/CHANGELOG.md index 219c8fc..f418c5d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Important changes v0.4.0 and above!!! * Main control mode, buttons and presets need to be configured again!!! +## [0.20.0] - (10.03.2024) +## Changes +- dynamically update temp unit +- prevent set out of range temperature for Air Conditioner +- cleanup + ## [0.19.0] - (02.03.2024) ## Changes - added support to control devices over MQTT protocol diff --git a/index.js b/index.js index 3f84854..08b3c31 100644 --- a/index.js +++ b/index.js @@ -41,32 +41,33 @@ class MelCloudPlatform { const debug = enableDebugMode ? log(`Account: ${accountName}, did finish launching.`) : false; //remove sensitive data - const config = { + const debugData = { ...account, user: 'removed', passwd: 'removed', mqttUser: 'removed', mqttPasswd: 'removed' }; - const debug1 = enableDebugMode ? log(`Account: ${accountName}, Config: ${JSON.stringify(config, null, 2)}`) : false; + const debug1 = enableDebugMode ? log(`Account: ${accountName}, Config: ${JSON.stringify(debugData, null, 2)}`) : false; //set refresh interval + const accountInfoFile = `${prefDir}/${accountName}_Account`; + const buildingsFile = `${prefDir}/${accountName}_Buildings`; const refreshInterval = account.refreshInterval * 1000 || 120000; //melcloud account - const melCloud = new MelCloud(prefDir, accountName, user, passwd, language, enableDebugMode, refreshInterval); + const melCloud = new MelCloud(prefDir, accountName, user, passwd, language, enableDebugMode, accountInfoFile, buildingsFile, refreshInterval); melCloud.on('checkDevicesListComplete', (accountInfo, contextKey, deviceInfo) => { const deviceId = deviceInfo.DeviceID.toString(); const deviceType = deviceInfo.Type; const deviceName = deviceInfo.DeviceName; const deviceTypeText = CONSTANTS.DeviceType[deviceType]; - const useFahrenheit = accountInfo.UseFahrenheit ? 1 : 0; const deviceInfoFile = `${prefDir}/${accountName}_Device_${deviceId}`; //melcloud devices switch (deviceType) { case 0: //Air Conditioner - const airConditioner = new DeviceAta(api, account, melCloud, accountInfo, accountName, contextKey, deviceId, deviceName, deviceTypeText, useFahrenheit, deviceInfoFile) + const airConditioner = new DeviceAta(api, account, melCloud, accountInfo, accountName, contextKey, deviceId, deviceName, deviceTypeText, accountInfoFile, deviceInfoFile) airConditioner.on('publishAccessory', (accessory) => { //publish device @@ -87,7 +88,7 @@ class MelCloudPlatform { }); break; case 1: //Heat Pump - const heatPump = new DeviceAtw(api, account, melCloud, accountInfo, accountName, contextKey, deviceId, deviceName, deviceTypeText, useFahrenheit, deviceInfoFile) + const heatPump = new DeviceAtw(api, account, melCloud, accountInfo, accountName, contextKey, deviceId, deviceName, deviceTypeText, accountInfoFile, deviceInfoFile) heatPump.on('publishAccessory', (accessory) => { //publish device @@ -108,7 +109,7 @@ class MelCloudPlatform { }); break; case 3: //Energy Recovery Ventilation - const energyRecoveryVentilation = new DeviceErv(api, account, melCloud, accountInfo, accountName, contextKey, deviceId, deviceName, deviceTypeText, useFahrenheit, deviceInfoFile) + const energyRecoveryVentilation = new DeviceErv(api, account, melCloud, accountInfo, accountName, contextKey, deviceId, deviceName, deviceTypeText, accountInfoFile, deviceInfoFile) energyRecoveryVentilation.on('publishAccessory', (accessory) => { //publish device diff --git a/package.json b/package.json index e6b322a..8c48d76 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "displayName": "MELCloud Control", "name": "homebridge-melcloud-control", - "version": "0.19.26", + "version": "0.20.0", "description": "Homebridge plugin to control Mitsubishi Air Conditioner, Heat Pump and Energy Recovery Ventilation.", "license": "MIT", "author": "grzegorz914", diff --git a/src/deviceata.js b/src/deviceata.js index 56cc08d..c19ccf5 100644 --- a/src/deviceata.js +++ b/src/deviceata.js @@ -7,7 +7,7 @@ const CONSTANTS = require('./constants.json'); let Accessory, Characteristic, Service, Categories, AccessoryUUID; class MelCloudDevice extends EventEmitter { - constructor(api, account, melCloud, accountInfo, accountName, contextKey, deviceId, deviceName, deviceTypeText, useFahrenheit, deviceInfoFile) { + constructor(api, account, melCloud, accountInfo, accountName, contextKey, deviceId, deviceName, deviceTypeText, accountInfoFile, deviceInfoFile) { super(); Accessory = api.platformAccessory; @@ -37,12 +37,10 @@ class MelCloudDevice extends EventEmitter { this.buttonsCount = this.buttons.length; this.startPrepareAccessory = true; - //temp unit - this.useFahrenheit = useFahrenheit; - //melcloud device this.melCloudAta = new MelCloudAta({ contextKey: contextKey, + accountInfoFile: accountInfoFile, deviceInfoFile: deviceInfoFile, debugLog: account.enableDebugMode }); @@ -64,7 +62,7 @@ class MelCloudDevice extends EventEmitter { this.model = modelIndoor ? modelIndoor : modelOutdoor ? modelOutdoor : `${deviceTypeText} ${deviceId}`; this.serialNumber = serialNumber; this.firmwareRevision = firmwareAppVersion; - }).on('deviceState', async (deviceData, deviceState) => { + }).on('deviceState', async (deviceData, deviceState, useFahrenheit) => { //device info const displayMode = this.displayMode; const hasAutomaticFanSpeed = deviceData.Device.HasAutomaticFanSpeed ?? false; @@ -91,7 +89,8 @@ class MelCloudDevice extends EventEmitter { this.modelSupportsHeat = modelSupportsHeat; this.modelSupportsDry = modelSupportsDry; this.temperatureIncrement = temperatureIncrement; - this.temperatureUnit = CONSTANTS.TemperatureDisplayUnits[this.useFahrenheit]; + this.temperatureUnit = CONSTANTS.TemperatureDisplayUnits[useFahrenheit]; + this.useFahrenheit = useFahrenheit; //device state const roomTemperature = deviceState.RoomTemperature; @@ -179,7 +178,7 @@ class MelCloudDevice extends EventEmitter { .updateCharacteristic(Characteristic.HeatingThresholdTemperature, setTemperature) .updateCharacteristic(Characteristic.CoolingThresholdTemperature, setTemperature) .updateCharacteristic(Characteristic.LockPhysicalControls, lockPhysicalControls) - .updateCharacteristic(Characteristic.TemperatureDisplayUnits, this.useFahrenheit); + .updateCharacteristic(Characteristic.TemperatureDisplayUnits, useFahrenheit); const updateRS = modelSupportsFanSpeed ? this.melCloudService.updateCharacteristic(Characteristic.RotationSpeed, fanSpeed) : false; const updateSM = swingFunction ? this.melCloudService.updateCharacteristic(Characteristic.SwingMode, swingMode) : false; }; @@ -200,7 +199,7 @@ class MelCloudDevice extends EventEmitter { .updateCharacteristic(Characteristic.TargetHeatingCoolingState, targetOperationMode) .updateCharacteristic(Characteristic.CurrentTemperature, roomTemperature) .updateCharacteristic(Characteristic.TargetTemperature, setTemperature) - .updateCharacteristic(Characteristic.TemperatureDisplayUnits, this.useFahrenheit); + .updateCharacteristic(Characteristic.TemperatureDisplayUnits, useFahrenheit); }; break; }; @@ -629,7 +628,6 @@ class MelCloudDevice extends EventEmitter { const autoDryFan = [modelSupportsDry ? 2 : 7, 7][this.autoHeatMode]; const heatFanDry = [7, modelSupportsDry ? 2 : 7][this.autoHeatMode]; const serviceName = `${deviceTypeText} ${accessoryName}`; - const temperatureUnit = this.temperatureUnit; switch (displayMode) { case 0: //Heater Cooler @@ -771,8 +769,8 @@ class MelCloudDevice extends EventEmitter { }); this.melCloudService.getCharacteristic(Characteristic.HeatingThresholdTemperature) .setProps({ - minValue: [0, 32][this.useFahrenheit], - maxValue: [31, 88][this.useFahrenheit], + minValue: 0, + maxValue: 31, minStep: this.temperatureIncrement }) .onGet(async () => { @@ -784,15 +782,15 @@ class MelCloudDevice extends EventEmitter { deviceState.SetTemperature = value; deviceState.EffectiveFlags = CONSTANTS.AirConditioner.EffectiveFlags.SetTemperature; await this.melCloudAta.send(deviceState); - const info = this.disableLogInfo ? false : this.emit('message', `Set heating threshold temperature: ${value}${temperatureUnit}`); + const info = this.disableLogInfo ? false : this.emit('message', `Set heating threshold temperature: ${value}${this.temperatureUnit}`); } catch (error) { this.emit('error', `Set heating threshold temperature error: ${error}`); }; }); this.melCloudService.getCharacteristic(Characteristic.CoolingThresholdTemperature) .setProps({ - minValue: [10, 50][this.useFahrenheit], - maxValue: [31, 88][this.useFahrenheit], + minValue: 10, + maxValue: 31, minStep: this.temperatureIncrement }) .onGet(async () => { @@ -804,7 +802,7 @@ class MelCloudDevice extends EventEmitter { deviceState.SetTemperature = value; deviceState.EffectiveFlags = CONSTANTS.AirConditioner.EffectiveFlags.SetTemperature; await this.melCloudAta.send(deviceState); - const info = this.disableLogInfo ? false : this.emit('message', `Set cooling threshold temperature: ${value}${temperatureUnit}`); + const info = this.disableLogInfo ? false : this.emit('message', `Set cooling threshold temperature: ${value}${this.temperatureUnit}`); } catch (error) { this.emit('error', `Set cooling threshold temperature error: ${error}`); }; @@ -905,8 +903,8 @@ class MelCloudDevice extends EventEmitter { }); this.melCloudService.getCharacteristic(Characteristic.TargetTemperature) .setProps({ - minValue: [0, 32][this.useFahrenheit], - maxValue: [31, 88][this.useFahrenheit], + minValue: 0, + maxValue: 31, minStep: this.temperatureIncrement }) .onGet(async () => { @@ -918,7 +916,7 @@ class MelCloudDevice extends EventEmitter { deviceState.SetTemperature = value; deviceState.EffectiveFlags = CONSTANTS.AirConditioner.EffectiveFlags.SetTemperature; await this.melCloudAta.send(deviceState); - const info = this.disableLogInfo ? false : this.emit('message', `Set temperature: ${value}${temperatureUnit}`); + const info = this.disableLogInfo ? false : this.emit('message', `Set temperature: ${value}${this.temperatureUnit}`); } catch (error) { this.emit('error', `Set temperature error: ${error}`); }; diff --git a/src/deviceatw.js b/src/deviceatw.js index ececcf5..cff25ac 100644 --- a/src/deviceatw.js +++ b/src/deviceatw.js @@ -7,7 +7,7 @@ const CONSTANTS = require('./constants.json'); let Accessory, Characteristic, Service, Categories, AccessoryUUID; class MelCloudDevice extends EventEmitter { - constructor(api, account, melCloud, accountInfo, accountName, contextKey, deviceId, deviceName, deviceTypeText, useFahrenheit, deviceInfoFile) { + constructor(api, account, melCloud, accountInfo, accountName, contextKey, deviceId, deviceName, deviceTypeText, accountInfoFile, deviceInfoFile) { super(); Accessory = api.platformAccessory; @@ -36,12 +36,10 @@ class MelCloudDevice extends EventEmitter { this.restFulConnected = false; this.mqttConnected = false; - //temp unit - this.useFahrenheit = useFahrenheit; - //melcloud device this.melCloudAtw = new MelCloudAtw({ contextKey: contextKey, + accountInfoFile: accountInfoFile, deviceInfoFile: deviceInfoFile, debugLog: account.enableDebugMode }); @@ -66,7 +64,7 @@ class MelCloudDevice extends EventEmitter { this.model = modelIndoor ? modelIndoor : modelOutdoor ? modelOutdoor : `${deviceTypeText} ${deviceId}`; this.serialNumber = serialNumber; this.firmwareRevision = firmwareAppVersion; - }).on('deviceState', async (deviceData, deviceState) => { + }).on('deviceState', async (deviceData, deviceState, useFahrenheit) => { //device info const displayMode = this.displayMode; const heatPumpName = 'Heat Pump'; @@ -118,7 +116,8 @@ class MelCloudDevice extends EventEmitter { this.caseHotWater = caseHotWater; this.caseZone2 = caseZone2; this.temperatureIncrement = temperatureIncrement; - this.temperatureUnit = CONSTANTS.TemperatureDisplayUnits[this.useFahrenheit]; + this.temperatureUnit = CONSTANTS.TemperatureDisplayUnits[useFahrenheit]; + this.useFahrenheit = useFahrenheit; //device state const setTemperatureZone1 = deviceState.SetTemperatureZone1; @@ -205,8 +204,8 @@ class MelCloudDevice extends EventEmitter { operationModeSetPropsMinValue = [0, 0, 1, 0][heatCoolModes]; operationModeSetPropsMaxValue = [2, 2, 2, 0][heatCoolModes]; operationModeSetPropsValidValues = [[0, 1, 2], [0, 1, 2], [1, 2], [0]][heatCoolModes]; - temperatureSetPropsMinValue = [0, 32][this.useFahrenheit]; - temperatureSetPropsMaxValue = [31, 88][this.useFahrenheit]; + temperatureSetPropsMinValue = 0; + temperatureSetPropsMaxValue = 31; break; case caseHotWater: //Hot Water - NORMAL, HEAT NOW currentOperationMode = !power ? 0 : operationMode === 1 ? 2 : [1, 2][forcedHotWaterMode]; //INACTIVE, IDLE, HEATING, COOLING @@ -218,8 +217,8 @@ class MelCloudDevice extends EventEmitter { operationModeSetPropsMinValue = 0; operationModeSetPropsMaxValue = 1; operationModeSetPropsValidValues = [0, 1]; - temperatureSetPropsMinValue = [0, 32][this.useFahrenheit]; - temperatureSetPropsMaxValue = [60, 140][this.useFahrenheit]; + temperatureSetPropsMinValue = 0; + temperatureSetPropsMaxValue = 60; break; case caseZone2: //Zone 2 - HEAT THERMOSTAT, HEAT FLOW, HEAT CURVE, COOL THERMOSTAT, COOL FLOW, FLOOR DRY UP currentOperationMode = !power ? 0 : idleZone2 ? 1 : [2, 2, 2, 3, 3, 2][operationModeZone2]; //INACTIVE, IDLE, HEATING, COOLING @@ -231,8 +230,8 @@ class MelCloudDevice extends EventEmitter { operationModeSetPropsMinValue = [0, 0, 1, 0][heatCoolModes]; operationModeSetPropsMaxValue = [2, 2, 2, 0][heatCoolModes]; operationModeSetPropsValidValues = [[0, 1, 2], [0, 1, 2], [1, 2], [0]][heatCoolModes]; - temperatureSetPropsMinValue = [0, 32][this.useFahrenheit]; - temperatureSetPropsMaxValue = [31, 88][this.useFahrenheit]; + temperatureSetPropsMinValue = 0; + temperatureSetPropsMaxValue = 31; break; default: //unknown zone detected this.emit('message', `Unknown zone: ${i} detected.`); @@ -247,7 +246,7 @@ class MelCloudDevice extends EventEmitter { .updateCharacteristic(Characteristic.TargetHeaterCoolerState, targetOperationMode) .updateCharacteristic(Characteristic.CurrentTemperature, roomTemperature) .updateCharacteristic(Characteristic.LockPhysicalControls, lockPhysicalControls) - .updateCharacteristic(Characteristic.TemperatureDisplayUnits, this.useFahrenheit); + .updateCharacteristic(Characteristic.TemperatureDisplayUnits, useFahrenheit); const updateHT = heatCoolModes === 0 || heatCoolModes === 1 ? this.melCloudServices[i].updateCharacteristic(Characteristic.HeatingThresholdTemperature, setTemperature) : false; const updateCT = heatCoolModes === 0 || heatCoolModes === 2 ? this.melCloudServices[i].updateCharacteristic(Characteristic.CoolingThresholdTemperature, setTemperature) : false; } @@ -275,8 +274,8 @@ class MelCloudDevice extends EventEmitter { operationModeSetPropsMinValue = [1, 1, 1, 0][heatCoolModes]; operationModeSetPropsMaxValue = [3, 3, 2, 0][heatCoolModes]; operationModeSetPropsValidValues = [[1, 2, 3], [1, 2, 3], [1, 2], [0]][heatCoolModes]; - temperatureSetPropsMinValue = [0, 32][this.useFahrenheit]; - temperatureSetPropsMaxValue = [31, 88][this.useFahrenheit]; + temperatureSetPropsMinValue = 0; + temperatureSetPropsMaxValue = 31; break; case caseHotWater: //Hot Water - NORMAL, HEAT NOW currentOperationMode = !power ? 0 : operationMode === 1 ? 1 : [0, 1][forcedHotWaterMode]; //OFF, HEAT, COOL @@ -287,8 +286,8 @@ class MelCloudDevice extends EventEmitter { operationModeSetPropsMinValue = 1; operationModeSetPropsMaxValue = 3; operationModeSetPropsValidValues = [1, 3]; - temperatureSetPropsMinValue = [0, 32][this.useFahrenheit]; - temperatureSetPropsMaxValue = [60, 140][this.useFahrenheit]; + temperatureSetPropsMinValue = 0; + temperatureSetPropsMaxValue = 60; break; case caseZone2: //Zone 2 - HEAT THERMOSTAT, HEAT FLOW, HEAT CURVE, COOL THERMOSTAT, COOL FLOW, FLOOR DRY UP currentOperationMode = !power ? 0 : idleZone2 ? 0 : [1, 1, 1, 2, 2, 1][operationModeZone2]; //OFF, HEAT, COOL @@ -299,8 +298,8 @@ class MelCloudDevice extends EventEmitter { operationModeSetPropsMinValue = [1, 1, 1, 0][heatCoolModes]; operationModeSetPropsMaxValue = [3, 3, 2, 0][heatCoolModes]; operationModeSetPropsValidValues = [[1, 2, 3], [1, 2, 3], [1, 2], [0]][heatCoolModes]; - temperatureSetPropsMinValue = [0, 32][this.useFahrenheit]; - temperatureSetPropsMaxValue = [31, 88][this.useFahrenheit]; + temperatureSetPropsMinValue = 0; + temperatureSetPropsMaxValue = 31; break; default: //unknown zone detected this.emit('message', `Unknown zone: ${i} detected.`); @@ -314,7 +313,7 @@ class MelCloudDevice extends EventEmitter { .updateCharacteristic(Characteristic.TargetHeatingCoolingState, targetOperationMode) .updateCharacteristic(Characteristic.CurrentTemperature, roomTemperature) .updateCharacteristic(Characteristic.TargetTemperature, setTemperature) - .updateCharacteristic(Characteristic.TemperatureDisplayUnits, this.useFahrenheit); + .updateCharacteristic(Characteristic.TemperatureDisplayUnits, useFahrenheit); } break; default: //unknown display type detected @@ -796,7 +795,6 @@ class MelCloudDevice extends EventEmitter { .setCharacteristic(Characteristic.FirmwareRevision, this.firmwareRevision); //melcloud services - const temperatureUnit = this.temperatureUnit; const zonesCount = this.zonesCount; const temperatureSensor = this.temperatureSensor; const buttonsConfigured = this.buttonsConfigured; @@ -978,7 +976,7 @@ class MelCloudDevice extends EventEmitter { }; const set = i > 0 ? await this.melCloudAtw.send(deviceState) : false; - const info = this.disableLogInfo || i === 0 ? false : this.emit('message', `${zoneName}, Set heating threshold temperature: ${value}${temperatureUnit}`); + const info = this.disableLogInfo || i === 0 ? false : this.emit('message', `${zoneName}, Set heating threshold temperature: ${value}${this.temperatureUnit}`); } catch (error) { this.emit('error', `${zoneName}, Set heating threshold temperature error: ${error}`); }; @@ -1018,7 +1016,7 @@ class MelCloudDevice extends EventEmitter { }; const set = i > 0 ? await this.melCloudAtw.send(deviceState) : false; - const info = this.disableLogInfo || i === 0 ? false : this.emit('message', `${zoneName}, Set cooling threshold temperature: ${value}${temperatureUnit}`); + const info = this.disableLogInfo || i === 0 ? false : this.emit('message', `${zoneName}, Set cooling threshold temperature: ${value}${this.temperatureUnit}`); } catch (error) { this.emit('error', `${zoneName}, Set cooling threshold temperature error: ${error}`); }; @@ -1236,7 +1234,7 @@ class MelCloudDevice extends EventEmitter { }; const set = i > 0 ? await this.melCloudAtw.send(deviceState) : false; - const info = this.disableLogInfo || i === 0 ? false : this.emit('message', `${zoneName}, Set temperature: ${value}${temperatureUnit}`); + const info = this.disableLogInfo || i === 0 ? false : this.emit('message', `${zoneName}, Set temperature: ${value}${this.temperatureUnit}`); } catch (error) { this.emit('error', `${zoneName}, Set temperature error: ${error}`); }; diff --git a/src/deviceerv.js b/src/deviceerv.js index fd992c0..691064d 100644 --- a/src/deviceerv.js +++ b/src/deviceerv.js @@ -7,7 +7,7 @@ const CONSTANTS = require('./constants.json'); let Accessory, Characteristic, Service, Categories, AccessoryUUID; class MelCloudDevice extends EventEmitter { - constructor(api, account, melCloud, accountInfo, accountName, contextKey, deviceId, deviceName, deviceTypeText, useFahrenheit, deviceInfoFile) { + constructor(api, account, melCloud, accountInfo, accountName, contextKey, deviceId, deviceName, deviceTypeText, accountInfoFile, deviceInfoFile) { super(); Accessory = api.platformAccessory; @@ -36,12 +36,10 @@ class MelCloudDevice extends EventEmitter { this.restFulConnected = false; this.mqttConnected = false; - //temp unit - this.useFahrenheit = useFahrenheit; - //melcloud device this.melCloudErv = new MelCloudErv({ contextKey: contextKey, + accountInfoFile: accountInfoFile, deviceInfoFile: deviceInfoFile, debugLog: account.enableDebugMode }); @@ -66,7 +64,7 @@ class MelCloudDevice extends EventEmitter { //device info - }).on('deviceState', async (deviceData, deviceState) => { + }).on('deviceState', async (deviceData, deviceState, useFahrenheit) => { //device info const displayMode = this.displayMode; const hasCoolOperationMode = deviceData.Device.HasCoolOperationMode ?? false; @@ -112,7 +110,8 @@ class MelCloudDevice extends EventEmitter { this.actualVentilationMode = actualVentilationMode; this.numberOfFanSpeeds = numberOfFanSpeeds; this.temperatureIncrement = temperatureIncrement; - this.temperatureUnit = CONSTANTS.TemperatureDisplayUnits[this.useFahrenheit]; + this.temperatureUnit = CONSTANTS.TemperatureDisplayUnits[useFahrenheit]; + this.useFahrenheit = useFahrenheit; //device state const roomTemperature = deviceState.RoomTemperature; @@ -141,7 +140,7 @@ class MelCloudDevice extends EventEmitter { let lockPhysicalControls = 0; //set temperature - const targetTemperature = hasCoolOperationMode || hasHeatOperationMode ? setTemperature : [20, 68][this.useFahrenheit]; + const targetTemperature = hasCoolOperationMode || hasHeatOperationMode ? setTemperature : 20; let operationModeSetPropsMinValue = 0; let operationModeSetPropsMaxValue = 3; let operationModeSetPropsValidValues = [0, 1, 2, 3]; @@ -186,7 +185,7 @@ class MelCloudDevice extends EventEmitter { .updateCharacteristic(Characteristic.CurrentTemperature, roomTemperature) .updateCharacteristic(Characteristic.RotationSpeed, fanSpeed) .updateCharacteristic(Characteristic.LockPhysicalControls, lockPhysicalControls) - .updateCharacteristic(Characteristic.TemperatureDisplayUnits, this.useFahrenheit); + .updateCharacteristic(Characteristic.TemperatureDisplayUnits, useFahrenheit); const updateHOM = hasHeatOperationMode ? this.melCloudService.updateCharacteristic(Characteristic.HeatingThresholdTemperature, targetTemperature) : false; const updateCOM = hasCoolOperationMode ? this.melCloudService.updateCharacteristic(Characteristic.CoolingThresholdTemperature, targetTemperature) : false; }; @@ -208,7 +207,7 @@ class MelCloudDevice extends EventEmitter { .updateCharacteristic(Characteristic.TargetHeatingCoolingState, targetOperationMode) .updateCharacteristic(Characteristic.CurrentTemperature, roomTemperature) .updateCharacteristic(Characteristic.TargetTemperature, targetTemperature) - .updateCharacteristic(Characteristic.TemperatureDisplayUnits, this.useFahrenheit); + .updateCharacteristic(Characteristic.TemperatureDisplayUnits, useFahrenheit); }; break; }; @@ -559,7 +558,6 @@ class MelCloudDevice extends EventEmitter { .setCharacteristic(Characteristic.FirmwareRevision, this.firmwareRevision); //melcloud services - const temperatureUnit = this.temperatureUnit; const displayMode = this.displayMode; const temperatureSensor = this.temperatureSensor; const buttonsConfigured = this.buttonsConfigured; @@ -687,8 +685,8 @@ class MelCloudDevice extends EventEmitter { if (hasHeatOperationMode) { this.melCloudService.getCharacteristic(Characteristic.HeatingThresholdTemperature) .setProps({ - minValue: [0, 32][this.useFahrenheit], - maxValue: [31, 88][this.useFahrenheit], + minValue: 0, + maxValue: 31, minStep: this.temperatureIncrement }) .onGet(async () => { @@ -700,7 +698,7 @@ class MelCloudDevice extends EventEmitter { deviceState.SetTemperature = value; deviceState.EffectiveFlags = CONSTANTS.Ventilation.EffectiveFlags.SetTemperature; await this.melCloudErv.send(deviceState); - const info = this.disableLogInfo ? false : this.emit('message', `Set heating threshold temperature: ${value}${temperatureUnit}`); + const info = this.disableLogInfo ? false : this.emit('message', `Set heating threshold temperature: ${value}${this.temperatureUnit}`); } catch (error) { this.emit('error', `Set heating threshold temperature error: ${error}`); }; @@ -710,8 +708,8 @@ class MelCloudDevice extends EventEmitter { if (hasCoolOperationMode) { this.melCloudService.getCharacteristic(Characteristic.CoolingThresholdTemperature) .setProps({ - minValue: [10, 50][this.useFahrenheit], - maxValue: [31, 88][this.useFahrenheit], + minValue: 10, + maxValue: 31, minStep: this.temperatureIncrement }) .onGet(async () => { @@ -723,7 +721,7 @@ class MelCloudDevice extends EventEmitter { deviceState.SetTemperature = value; deviceState.EffectiveFlags = CONSTANTS.Ventilation.EffectiveFlags.SetTemperature; await this.melCloudErv.send(deviceState); - const info = this.disableLogInfo ? false : this.emit('message', `Set cooling threshold temperature: ${value}${temperatureUnit}`); + const info = this.disableLogInfo ? false : this.emit('message', `Set cooling threshold temperature: ${value}${this.temperatureUnit}`); } catch (error) { this.emit('error', `Set cooling threshold temperature error: ${error}`); }; @@ -824,8 +822,8 @@ class MelCloudDevice extends EventEmitter { }); this.melCloudService.getCharacteristic(Characteristic.TargetTemperature) .setProps({ - minValue: [0, 32][this.useFahrenheit], - maxValue: [31, 88][this.useFahrenheit], + minValue: 0, + maxValue: 31, minStep: this.temperatureIncrement }) .onGet(async () => { @@ -837,7 +835,7 @@ class MelCloudDevice extends EventEmitter { deviceState.SetTemperature = value; deviceState.EffectiveFlags = CONSTANTS.Ventilation.EffectiveFlags.SetTemperature; await this.melCloudErv.send(deviceState); - const info = this.disableLogInfo ? false : this.emit('message', `Set temperature: ${value}${temperatureUnit}`); + const info = this.disableLogInfo ? false : this.emit('message', `Set temperature: ${value}${this.temperatureUnit}`); } catch (error) { this.emit('error', `Set temperature error: ${error}`); }; diff --git a/src/melcloud.js b/src/melcloud.js index 285d228..de3a631 100644 --- a/src/melcloud.js +++ b/src/melcloud.js @@ -7,11 +7,9 @@ const EventEmitter = require('events'); const CONSTANTS = require('./constants.json'); class MelCloud extends EventEmitter { - constructor(prefDir, accountName, user, passwd, language, enableDebugMode, refreshInterval) { + constructor(prefDir, accountName, user, passwd, language, enableDebugMode, accountInfoFile, buildingsFile, refreshInterval) { super(); - this.accountInfoFile = `${prefDir}/${accountName}_Account`; - const buildingsFile = `${prefDir}/${accountName}_Buildings`; - const devicesId = []; + this.accountInfoFile = accountInfoFile; const refreshIntervalSec = refreshInterval / 1000; this.refreshInterval = refreshInterval; @@ -39,6 +37,7 @@ class MelCloud extends EventEmitter { }) }); + const devicesId = []; this.on('connect', async () => { try { const accountData = await axiosInstanceLogin(CONSTANTS.ApiUrls.ClientLogin, options); @@ -47,8 +46,8 @@ class MelCloud extends EventEmitter { const contextKey = accountInfo.ContextKey; //remove sensitive data - const config = { - ...account.LoginData, + const debugData = { + ...accountInfo, ContextKey: 'removed', ClientId: 'removed', Client: 'removed', @@ -56,7 +55,7 @@ class MelCloud extends EventEmitter { MapLongitude: 'removed', MapLatitude: 'removed' }; - const debug = enableDebugMode ? this.emit('debug', `MELCloud Info: ${JSON.stringify(config, null, 2)}`) : false; + const debug = enableDebugMode ? this.emit('debug', `MELCloud Info: ${JSON.stringify(debugData, null, 2)}`) : false; if (contextKey === undefined || contextKey === null) { this.emit('message', `context key: ${contextKey}, missing, reconnect in ${refreshIntervalSec}.`) @@ -103,7 +102,7 @@ class MelCloud extends EventEmitter { this.contextKey = contextKey; //save melcloud info to the file - await this.saveData(this.accountInfoFile, accountInfo); + await this.saveData(accountInfoFile, accountInfo); //check devices list await new Promise(resolve => setTimeout(resolve, 500)); diff --git a/src/melcloudata.js b/src/melcloudata.js index 266c3d8..7d5b826 100644 --- a/src/melcloudata.js +++ b/src/melcloudata.js @@ -10,6 +10,7 @@ class MelCloudAta extends EventEmitter { constructor(config) { super(); const contextKey = config.contextKey; + const accountInfoFile = config.accountInfoFile; const deviceInfoFile = config.deviceInfoFile; const debugLog = config.debugLog; @@ -34,9 +35,26 @@ class MelCloudAta extends EventEmitter { this.on('checkDevice', async () => { try { + //read account info from file + const accountInfo = await this.readData(accountInfoFile); + + //remove sensitive data + const debugData = { + ...accountInfo, + ContextKey: 'removed', + ClientId: 'removed', + Client: 'removed', + Name: 'removed', + MapLongitude: 'removed', + MapLatitude: 'removed' + }; + const debug = debugLog ? this.emit('debug', `Account Info: ${JSON.stringify(debugData, null, 2)}`) : false; + const useFahrenheit = accountInfo.UseFahrenheit ? 1 : 0; + this.useFahrenheit = useFahrenheit; + //read device info from file const deviceData = await this.readData(deviceInfoFile); - const debug = debugLog ? this.emit('debug', `Info: ${JSON.stringify(deviceData, null, 2)}`) : false; + const debug1 = debugLog ? this.emit('debug', `Device Info: ${JSON.stringify(deviceData, null, 2)}`) : false; if (!deviceData) { this.checkDevice(); @@ -327,7 +345,6 @@ class MelCloudAta extends EventEmitter { Power: power, Offline: offline } - const debug1 = debugLog ? this.emit('debug', `State: ${JSON.stringify(deviceState, null, 2)}`) : false; //restFul this.emit('restFul', 'state', deviceState); @@ -342,9 +359,10 @@ class MelCloudAta extends EventEmitter { return; } this.deviceData = deviceData; + const debug2 = debugLog ? this.emit('debug', `Device State: ${JSON.stringify(deviceState, null, 2)}`) : false; //emit state changes - this.emit('deviceState', deviceData, deviceState); + this.emit('deviceState', deviceData, deviceState, useFahrenheit); this.checkDevice(); } catch (error) { this.emit('error', `Check device error: ${error}.`); @@ -375,13 +393,42 @@ class MelCloudAta extends EventEmitter { send(deviceState) { return new Promise(async (resolve, reject) => { try { + + //prevent set wrong temp + const minTempCoolDry = this.deviceData.Device.MinTempCoolDry ?? 16; + const maxTempCoolDry = this.deviceData.Device.MaxTempCoolDry ?? 31; + const minTempHeat = this.deviceData.Device.MinTempHeat ?? 10; + const maxTempHeat = this.deviceData.Device.MaxTempHeat ?? 31; + const minTempAutomatic = this.deviceData.Device.MinTempAutomatic ?? 16; + const maxTempAutomatic = this.deviceData.Device.MaxTempAutomatic ?? 31; + switch (deviceState.OperationMode) {//operating mode 0, HEAT, DRY, COOL, 4, 5, 6, FAN, AUTO, ISEE HEAT, ISEE DRY, ISEE COOL + case 1: + deviceState.SetTemperature = deviceState.SetTemperature < minTempHeat ? minTempHeat : deviceState.SetTemperature; + deviceState.SetTemperature = deviceState.SetTemperature > maxTempHeat ? maxTempHeat : deviceState.SetTemperature; + break; + case 2: + deviceState.SetTemperature = deviceState.SetTemperature < minTempCoolDry ? minTempCoolDry : deviceState.SetTemperature; + deviceState.SetTemperature = deviceState.SetTemperature > maxTempCoolDry ? maxTempCoolDry : deviceState.SetTemperature; + break; + case 3: + deviceState.SetTemperature = deviceState.SetTemperature < minTempCoolDry ? minTempCoolDry : deviceState.SetTemperature; + deviceState.SetTemperature = deviceState.SetTemperature > maxTempCoolDry ? maxTempCoolDry : deviceState.SetTemperature; + break; + case 8: + deviceState.SetTemperature = deviceState.SetTemperature < minTempAutomatic ? minTempAutomatic : deviceState.SetTemperature; + deviceState.SetTemperature = deviceState.SetTemperature > maxTempAutomatic ? maxTempAutomatic : deviceState.SetTemperature; + break; + default: + break; + }; + deviceState.HasPendingCommand = true; const options = { data: deviceState }; await this.axiosInstancePost(CONSTANTS.ApiUrls.SetAta, options); - this.emit('deviceState', this.deviceData, deviceState); + this.emit('deviceState', this.deviceData, deviceState, this.useFahrenheit); resolve(); } catch (error) { reject(error); diff --git a/src/melcloudatw.js b/src/melcloudatw.js index 29aa456..853f37f 100644 --- a/src/melcloudatw.js +++ b/src/melcloudatw.js @@ -10,6 +10,7 @@ class MelCloudAtw extends EventEmitter { constructor(config) { super(); const contextKey = config.contextKey; + const accountInfoFile = config.accountInfoFile; const deviceInfoFile = config.deviceInfoFile; const debugLog = config.debugLog; @@ -34,9 +35,26 @@ class MelCloudAtw extends EventEmitter { this.on('checkDevice', async () => { try { + //read account info from file + const accountInfo = await this.readData(accountInfoFile); + + //remove sensitive data + const debugData = { + ...accountInfo, + ContextKey: 'removed', + ClientId: 'removed', + Client: 'removed', + Name: 'removed', + MapLongitude: 'removed', + MapLatitude: 'removed' + }; + const debug = debugLog ? this.emit('debug', `Account Info: ${JSON.stringify(debugData, null, 2)}`) : false; + const useFahrenheit = accountInfo.UseFahrenheit ? 1 : 0; + this.useFahrenheit = useFahrenheit; + //read device info from file const deviceData = await this.readData(deviceInfoFile); - const debug = debugLog ? this.emit('debug', `Info: ${JSON.stringify(deviceData, null, 2)}`) : false; + const debug1 = debugLog ? this.emit('debug', `Device Info: ${JSON.stringify(deviceData, null, 2)}`) : false; if (!deviceData) { this.checkDevice(); @@ -398,7 +416,6 @@ class MelCloudAtw extends EventEmitter { Power: power, Offline: offline } - const debug1 = debugLog ? this.emit('debug', `State: ${JSON.stringify(deviceState, null, 2)}`) : false; //restFul this.emit('restFul', 'state', deviceState); @@ -413,9 +430,10 @@ class MelCloudAtw extends EventEmitter { return; } this.deviceData = deviceData; + const debug2 = debugLog ? this.emit('debug', `Device State: ${JSON.stringify(deviceState, null, 2)}`) : false; //emit state changes - this.emit('deviceState', deviceData, deviceState); + this.emit('deviceState', deviceData, deviceState, useFahrenheit); this.checkDevice(); } catch (error) { this.emit('error', `Check device error: ${error}.`); @@ -452,7 +470,7 @@ class MelCloudAtw extends EventEmitter { }; await this.axiosInstancePost(CONSTANTS.ApiUrls.SetAtw, options); - this.emit('deviceState', this.deviceData, deviceState); + this.emit('deviceState', this.deviceData, deviceState, this.useFahrenheit); resolve(); } catch (error) { reject(error); diff --git a/src/melclouderv.js b/src/melclouderv.js index dcfb0e1..e9b597c 100644 --- a/src/melclouderv.js +++ b/src/melclouderv.js @@ -10,6 +10,7 @@ class MelCloudErv extends EventEmitter { constructor(config) { super(); const contextKey = config.contextKey; + const accountInfoFile = config.accountInfoFile; const deviceInfoFile = config.deviceInfoFile; const debugLog = config.debugLog; @@ -34,9 +35,26 @@ class MelCloudErv extends EventEmitter { this.on('checkDevice', async () => { try { + //read account info from file + const accountInfo = await this.readData(accountInfoFile); + + //remove sensitive data + const debugData = { + ...accountInfo, + ContextKey: 'removed', + ClientId: 'removed', + Client: 'removed', + Name: 'removed', + MapLongitude: 'removed', + MapLatitude: 'removed' + }; + const debug = debugLog ? this.emit('debug', `Account Info: ${JSON.stringify(debugData, null, 2)}`) : false; + const useFahrenheit = accountInfo.UseFahrenheit ? 1 : 0; + this.useFahrenheit = useFahrenheit; + //read device info from file const deviceData = await this.readData(deviceInfoFile); - const debug = debugLog ? this.emit('debug', `Info: ${JSON.stringify(deviceData, null, 2)}`) : false; + const debug1 = debugLog ? this.emit('debug', `Device Info: ${JSON.stringify(deviceData, null, 2)}`) : false; if (!deviceData) { this.checkDevice(); @@ -315,7 +333,6 @@ class MelCloudErv extends EventEmitter { Power: power, Offline: offline, } - const debug1 = debugLog ? this.emit('debug', `State: ${JSON.stringify(deviceState, null, 2)}`) : false; //restFul this.emit('restFul', 'state', deviceState); @@ -330,9 +347,10 @@ class MelCloudErv extends EventEmitter { return; } this.deviceData = deviceData; + const debug2 = debugLog ? this.emit('debug', `Device State: ${JSON.stringify(deviceState, null, 2)}`) : false; //emit state changes - this.emit('deviceState', deviceData, deviceState); + this.emit('deviceState', deviceData, deviceState, useFahrenheit); this.checkDevice(); } catch (error) { this.emit('error', `Check device error: ${error}.`); @@ -369,7 +387,7 @@ class MelCloudErv extends EventEmitter { }; await this.axiosInstancePost(CONSTANTS.ApiUrls.SetErv, options); - this.emit('deviceState', this.deviceData, deviceState); + this.emit('deviceState', this.deviceData, deviceState, this.useFahrenheit); resolve(); } catch (error) { reject(error);