UNPKG

@pst-on-npm/homebridge-enocean

Version:
260 lines • 13.3 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.WindowCoveringAccessory = void 0; const EnoCore = __importStar(require("enocean-core")); const InformationServiceHelper_1 = require("../serviceHelper/InformationServiceHelper"); const EnoTransmittingAccessory_1 = require("./EnoTransmittingAccessory"); const EnoMessageFactory_1 = require("../enocean/EnoMessageFactory"); /** * EnoTemperatureSensorAccessory * An instance of this class is created for each temperature sensor * Creates a relative humidity service as well depending on EEP */ class WindowCoveringAccessory extends EnoTransmittingAccessory_1.EnoTransmittingAccessory { _service; _interval; _positionReportTimeout; _travelVelocity; _confirmedPosition; _currentPosition; _positionState; _targetPosition; /** * Constructs a new instance of the WindowCoveringAccessory class. * * @param platform - The EnOceanHomebridgePlatform instance. * @param accessory - The PlatformAccessory instance with EnoAccessoryContext. * @param config - The DeviceConfig instance. * * Initializes the accessory context and sets up the initial position, target position, * position state, and travel velocity. Configures the accessory information service * and registers handlers for the required characteristics of the WindowCovering service. */ constructor(platform, accessory, config) { super(platform, accessory, config); const hap = platform.api.hap; if (accessory.context.currentPosition === undefined) { accessory.context.currentPosition = 100; } this._currentPosition = this._targetPosition = accessory.context.currentPosition; this._positionState = hap.Characteristic.PositionState.STOPPED; this._travelVelocity = 100 / (this.config.time ?? 30); // Set accessory information service InformationServiceHelper_1.InformationServiceHelper.setupService(platform, accessory, config); // Get the service if it exists, otherwise create a new service this._service = this.accessory.getService(hap.Service.WindowCovering) || this.accessory.addService(hap.Service.WindowCovering, config.name); this._service.setCharacteristic(hap.Characteristic.Name, accessory.displayName); // Each service must implement at-minimum the "required characteristics" for the given service type // see https://developers.homebridge.io/#/service/WindowCovering // Register handlers for the Characteristics this._service.getCharacteristic(hap.Characteristic.CurrentPosition) .onGet(() => this.getProperty(this._currentPosition)); this._service.getCharacteristic(hap.Characteristic.PositionState) .onGet(() => this.getProperty(this._positionState)); this._service.getCharacteristic(hap.Characteristic.TargetPosition) .onGet(() => this.getProperty(this._targetPosition)) .onSet((value) => this.targetPosition_onSet(value)); } _sendTimeout; async targetPosition_onSet(value) { this.platform.log.info(`${this.accessory.displayName}: SET targetPosition ${value}`); if (value !== this._targetPosition || value === 100 || value === 0) { this._targetPosition = value; if (this._sendTimeout) { clearTimeout(this._sendTimeout); } this._sendTimeout = setTimeout(() => { if (this._gateway && this._senderId) { let erp1 = undefined; if (this.config.eepId.rorg === EnoCore.RORGs.FOURBS) { // Send Manufacturer specific 4BS message const v = this._travelVelocity; let time_s = Math.abs(this._targetPosition - this._currentPosition) / v; let cmd = this._targetPosition > this._currentPosition ? 1 : 2; if (this._targetPosition === 100 || this._targetPosition === 0) { // Special case final positions cmd = (this._targetPosition === 100) ? 1 : 2; time_s = 105 / v; } erp1 = EnoMessageFactory_1.EnoMessageFactory.newFourBSGatewayBlindsMessageEltako(cmd, time_s); } else if (this.config.eepId.rorg === EnoCore.RORGs.VLD && this.config.eepId.func === 0x05) { // Blinds Control for position and angle erp1 = EnoMessageFactory_1.EnoMessageFactory.newVldBlindsControlMessage(1, 100 - this._targetPosition, 127); } if (erp1 !== undefined) { this.sendErp1Telegram(erp1); } } }, 1200); } } EnoGateway_eepMessageReceived(message) { this.platform.log.debug(`${this.accessory.displayName}: ${message.toString()}`); if (message.values.currentPosition !== undefined) { this.EnoGateway_updateByPositionReport(100 - message.values.currentPosition); } else if (message.values.state !== undefined) { let needInterval = false; const intervalDelay_s = 10 / this._travelVelocity; let state = this.platform.Characteristic.PositionState.STOPPED; let interpolatedPos = this._currentPosition; let confirmedPosition = undefined; switch (message.values.state) { case 'up': state = this.platform.Characteristic.PositionState.INCREASING; needInterval = true; break; case 'down': state = this.platform.Characteristic.PositionState.DECREASING; needInterval = true; break; case 'open': state = 2; interpolatedPos = 100; state = this.platform.Characteristic.PositionState.STOPPED; needInterval = false; confirmedPosition = 100; break; case 'closed': state = this.platform.Characteristic.PositionState.STOPPED; interpolatedPos = 0; needInterval = false; confirmedPosition = 0; break; default: state = this.platform.Characteristic.PositionState.STOPPED; needInterval = false; if (this._confirmedPosition !== undefined && message.values.stoppedAfter_s !== undefined) { confirmedPosition = this._confirmedPosition + (this._travelVelocity * message.values.stoppedAfter_s); confirmedPosition = Math.max(0, Math.min(100, confirmedPosition)); } break; } if ((this._interval !== undefined) !== needInterval) { if (needInterval) { this._interval = setInterval(() => { if (message.values.state === 'up') { interpolatedPos += this._travelVelocity * intervalDelay_s; } else { interpolatedPos -= this._travelVelocity * intervalDelay_s; } interpolatedPos = Math.max(0, Math.min(100, interpolatedPos)); this._currentPosition = Math.round(interpolatedPos); if (interpolatedPos === 100 || interpolatedPos === 0) { clearInterval(this._interval); this._interval = undefined; } this._currentPosition = this._targetPosition = Math.round(interpolatedPos); this.logInfoCurrentPositionAndState('(interpolated)'); this._service.updateCharacteristic(this.hap.Characteristic.CurrentPosition, this._currentPosition); this._service.getCharacteristic(this.hap.Characteristic.TargetPosition) .sendEventNotification(this._targetPosition); }, intervalDelay_s * 1000); } else { clearInterval(this._interval); this._interval = undefined; } } if (confirmedPosition !== undefined) { this._confirmedPosition = confirmedPosition; this._targetPosition = confirmedPosition; interpolatedPos = confirmedPosition; this.platform.log.info(`${this.accessory.displayName}: position confirmed: ${interpolatedPos}`); } this._currentPosition = Math.round(interpolatedPos); this._service.updateCharacteristic(this.hap.Characteristic.CurrentPosition, this._currentPosition); this._service.getCharacteristic(this.hap.Characteristic.TargetPosition) .sendEventNotification(this._targetPosition); this.accessory.context.currentPosition = this._currentPosition; this._positionState = state; this._service.updateCharacteristic(this.hap.Characteristic.PositionState, this._positionState); this.logInfoCurrentPositionAndState(); } } EnoGateway_updateByPositionReport(currentPosition) { let state = this.platform.Characteristic.PositionState.STOPPED; if (this._positionReportTimeout !== undefined) { clearTimeout(this._positionReportTimeout); this._positionReportTimeout = undefined; } if (this._currentPosition !== undefined) { const delta = currentPosition - this._currentPosition; if (delta > 0) { state = this.platform.Characteristic.PositionState.INCREASING; } else if (delta < 0) { state = this.platform.Characteristic.PositionState.DECREASING; } } if (currentPosition === 0 || currentPosition === 100) { state = this.platform.Characteristic.PositionState.STOPPED; } if (state !== this.platform.Characteristic.PositionState.STOPPED) { this._positionReportTimeout = setTimeout(() => { // Recursively call this method again to detect 'STOPPED' this.EnoGateway_updateByPositionReport(currentPosition); }, 3000); } this._positionState = state; this._service.updateCharacteristic(this.hap.Characteristic.PositionState, this._positionState); if (state === this.platform.Characteristic.PositionState.STOPPED) { this._targetPosition = currentPosition; this._service.updateCharacteristic(this.hap.Characteristic.TargetPosition, this._targetPosition); } this._currentPosition = currentPosition; this._service.updateCharacteristic(this.hap.Characteristic.CurrentPosition, this._currentPosition); this.accessory.context.currentPosition = this._currentPosition; this.logInfoCurrentPositionAndState(); } logInfoCurrentPositionAndState(suffix) { const state = this._positionState === 2 ? 'STOPPED' : this._positionState === 1 ? 'INCREASING' : 'DECREASING'; let message = `${this.accessory.displayName}: UPDATE currentPosition=${this._currentPosition} positionState=${state}`; if (suffix !== undefined) { message += ` ${suffix}`; } this.platform.log.info(message); } } exports.WindowCoveringAccessory = WindowCoveringAccessory; //# sourceMappingURL=WindowCoveringAccessory.js.map