diff --git a/lib/window_covering_accessory.js b/lib/window_covering_accessory.js index 00ec11a2..984f763b 100644 --- a/lib/window_covering_accessory.js +++ b/lib/window_covering_accessory.js @@ -17,6 +17,12 @@ class WindowCoveringAccessory extends BaseAccessory { ); this.statusArr = deviceConfig.status; + this.movingStartTime = null; + this.movingDuration = null; + this.updateTimer = null; + this.cachedHbValue = 0; + this.totalOpenDuration = 30; + this.refreshAccessoryServiceIfNeed(this.statusArr, false); }; @@ -35,11 +41,13 @@ class WindowCoveringAccessory extends BaseAccessory { // Characteristic.TargetPosition if (statusMap.code === 'percent_control') { this.percentControlMap = statusMap - this.normalAsync(Characteristic.TargetPosition, this._getCorrectPercent(this.percentControlMap.value)); + const percent = this._getCorrectPercent(this.percentControlMap.value); + this.cachedHbValue = percent; + this.normalAsync(Characteristic.TargetPosition, percent); if (!this._isHaveDPCodeOfPercentState()) { // Characteristic.CurrentPosition - this.normalAsync(Characteristic.CurrentPosition, this._getCorrectPercent(this.percentControlMap.value)); + this.normalAsync(Characteristic.CurrentPosition, percent); } } @@ -47,6 +55,7 @@ class WindowCoveringAccessory extends BaseAccessory { if (statusMap.code === 'position') { this.percentControlMap = statusMap const percent = this._getCorrectPercent(parseInt(this.percentControlMap.value)) + this.cachedHbValue = percent; this.normalAsync(Characteristic.TargetPosition, percent); if (!this._isHaveDPCodeOfPercentState()) { @@ -60,9 +69,7 @@ class WindowCoveringAccessory extends BaseAccessory { this.positionMap = statusMap this.normalAsync(Characteristic.CurrentPosition, this._getCorrectPercent(this.positionMap.value)); - // Characteristic.PositionState - // let hbValue = this.getHomeBridgeParam(Characteristic.PositionState, this._getCorrectPercent(this.positionMap.value)); - // this.normalAsync(Characteristic.PositionState, hbValue); + this.normalAsync(Characteristic.PositionState, Characteristic.PositionState.STOPPED); } } } @@ -82,11 +89,17 @@ class WindowCoveringAccessory extends BaseAccessory { .on('set', (hbValue, callback) => { let percentValue = this._getCorrectPercent(hbValue) let tuyaParam = this.getTuyaParam(name, percentValue); + this.platform.tuyaOpenApi.sendCommand(this.deviceId, tuyaParam).then(() => { //store homebridge value + // this.log.debug("set blinds from: " + this.cachedHbValue + "; to: " + hbValue) this.setCachedState(name, hbValue); - // //store targetPosition value - // this.targetPosition = percentValue; + + this.movingStartTime = new Date().getTime(); + let movingDuration = Math.abs(hbValue - this.cachedHbValue) * (this.totalOpenDuration / 100 * 1000); + this.cachedHbValue = hbValue; + + this.startUpdateTimer(hbValue, movingDuration); callback(); }).catch((error) => { this.log.error('[SET][%s] Characteristic Error: %s', this.homebridgeAccessory.displayName, error); @@ -96,8 +109,6 @@ class WindowCoveringAccessory extends BaseAccessory { }); } - - /** * get Tuya param from HomeBridge param */ @@ -121,25 +132,6 @@ class WindowCoveringAccessory extends BaseAccessory { }; } - /** - * get HomeBridge param from tuya param - */ - // getHomeBridgeParam(name, tuyaParam) { - // if (Characteristic.PositionState === name) { - // if (this.targetPosition) { - // if (this.targetPosition > tuyaParam) { - // return Characteristic.PositionState.INCREASING; - // } else if (this.targetPosition < tuyaParam) { - // return Characteristic.PositionState.DECREASING; - // } else { - // return Characteristic.PositionState.STOPPED; - // } - // } else { - // return Characteristic.PositionState.STOPPED; - // } - // } - // } - /** * update HomeBridge state * @param {*} name HomeBridge Name @@ -160,14 +152,13 @@ class WindowCoveringAccessory extends BaseAccessory { _getCorrectPercent(value) { var percent = value; if (this.fullySituationMap && this.fullySituationMap.value === 'fully_open') { - return percent + return percent; } else { percent = 100 - percent; - return percent + return percent; } } - //Check whether the device supports percent_state dp code _isHaveDPCodeOfPercentState() { const percentStateDic = this.statusArr.find((item, index) => { return item.code.indexOf("percent_state") != -1 }); @@ -178,29 +169,36 @@ class WindowCoveringAccessory extends BaseAccessory { } } + startUpdateTimer(targetValue, movingDuration) { + this.stopUpdateTimer(); + let hbValue; + if (this._getCorrectPercent(targetValue) > this._getCorrectPercent(this.cachedHbValue)) { + hbValue = Characteristic.PositionState.INCREASING; + } else if (this._getCorrectPercent(targetValue) < this._getCorrectPercent(this.cachedHbValue)) { + hbValue = Characteristic.PositionState.DECREASING; + } + this.normalAsync(Characteristic.PositionState, hbValue); + this.updateTimer = setTimeout(this.estimatedMovementStop.bind(this), movingDuration); + } - //Check Motor Reversed - // _isMotorReversed() { - // let isMotorReversed - // for (const statusMap of this.statusArr) { - // switch (statusMap.code) { - // case 'control_back_mode': - // if (statusMap.value === 'forward') { - // isMotorReversed = false; - // } else { - // isMotorReversed = true; - // } - // break; - // case 'opposite': - // case 'control_back': - // isMotorReversed = statusMap.value; - // break; - // default: - // break; - // } - // } - // return isMotorReversed; - // } + stopUpdateTimer() { + if (this.updateTimer) { + clearTimeout(this.updateTimer); + this.updateTimer = null; + } + } + + estimatedMovementStop() { + let refresh = this.isRefresh; + this.isRefresh = true; + this.normalAsync(Characteristic.TargetPosition, this.cachedHbValue); + this.normalAsync(Characteristic.CurrentPosition, this.cachedHbValue); + this.isRefresh = refresh; + + this.movingStartTime = null; + this.movingDuration = null; + this.stopUpdateTimer(); + } /** * Tuya MQTT update device status