UNPKG

homebridge-loxone-ws-adv-cstm

Version:

Websocket based Loxone plugin for homebridge advanced version (https://github.com/nfarina/homebridge)

149 lines (116 loc) 5.3 kB
const request = require("request"); const BlindsItem = function(widget,platform,homebridge) { this.platform = platform; this.uuidAction = widget.uuidAction; //to control a dimmer, use the uuidAction this.stateUuid = widget.states.position; //a blind always has a state called position, which is the uuid which will receive the event to read this.initialValue = true; this.inControl = false; //100 means fully open this.currentPosition = 100; this.targetPosition = 100; this.startedPosition = 100; BlindsItem.super_.call(this, widget,platform,homebridge); this.positionState = this.homebridge.hap.Characteristic.PositionState.STOPPED; this.gotCallBack = false; }; // Register a listener to be notified of changes in this items value BlindsItem.prototype.initListener = function() { this.platform.ws.registerListenerForUUID(this.stateUuid, this.callBack.bind(this)); }; BlindsItem.prototype.callBack = function(value) { //function that gets called by the registered ws listener //console.log("Got new state for blind " + value); this.gotCallBack = true //incomign values from blinds are decimal (0 - 1) value *= 100; //in Homekit, 100% means OPEN while in Loxone this means CLOSED: reverse value = parseInt(100 - value); if(this.initialValue) { //this is the initial value. therfore, also set current targetValue on the same this.targetPosition = value; this.initialValue = false; } //if extenal actor changed the blinds, it's important that we set the targetvalue to the new real situation if(!this.inControl) { this.targetPosition = value; } //define states for Homekit const delta = Math.abs(parseInt(value) - this.targetPosition); let ps = this.homebridge.hap.Characteristic.PositionState.INCREASING; if (delta < 3) { //blinds don't always stop at the exact position, so take a margin of 3% here ps = this.homebridge.hap.Characteristic.PositionState.STOPPED; } else if (parseInt(value) > this.targetPosition){ ps = this.homebridge.hap.Characteristic.PositionState.DECREASING; } this.currentPosition = value; //also make sure this change is directly communicated to HomeKit this.otherService .getCharacteristic(this.homebridge.hap.Characteristic.PositionState) .updateValue(ps); this.otherService .getCharacteristic(this.homebridge.hap.Characteristic.TargetPosition) .updateValue(parseInt(this.targetPosition)); this.otherService .getCharacteristic(this.homebridge.hap.Characteristic.CurrentPosition) .updateValue(value); }; BlindsItem.prototype.getOtherServices = function() { const otherService = new this.homebridge.hap.Service.WindowCovering(); otherService.getCharacteristic(this.homebridge.hap.Characteristic.CurrentPosition) .on('get', this.getItemCurrentPosition.bind(this)) .updateValue(this.currentPosition); otherService.getCharacteristic(this.homebridge.hap.Characteristic.TargetPosition) .on('set', this.setItem.bind(this)) .on('get', this.getItemTargetPosition.bind(this)) .updateValue(this.currentPosition); otherService.getCharacteristic(this.homebridge.hap.Characteristic.PositionState) .on('get', this.getItemPositionState.bind(this)) .updateValue(this.positionState); return otherService; }; BlindsItem.prototype.getItemPositionState = function(callback) { callback(undefined,this.positionState); }; BlindsItem.prototype.getItemTargetPosition = function(callback) { callback(undefined,this.targetPosition); }; BlindsItem.prototype.getItemCurrentPosition = function(callback) { callback(undefined,this.currentPosition); }; BlindsItem.prototype.setItem = function(value, callback) { this.gotCallBack = false; //sending new state (pct closed) to loxone const self = this; //set a flag that we're in control. this way we'll know if the action is coming from Homekit or from external actor (eg Loxone app) //this flag is removed after 20 seconds (increase if you have really long or slow blinds ;) this.inControl =true; setTimeout(() => { self.inControl = false; }, 20000); this.startedPosition = this.currentPosition; this.targetPosition = parseInt(value); let command = 0; if (typeof value === 'boolean') { command = value ? 'FullUp' : 'FullDown'; } else { //reverse again the value command = `ManualPosition/${100 - value}`; } this.log(`[blinds] iOS - send message to ${this.name}: ${command}`); this.platform.ws.sendCommand(this.uuidAction, command); callback(); if(this.targetPosition != this.startedPosition) { setTimeout(function(){ if(!self.gotCallBack) { var command = 0; if (typeof value === 'boolean') { command = value ? 'FullUp' : 'FullDown'; } else { //reverse again the value command = "ManualPosition/" + (100 - value - 1); } self.platform.ws.sendCommand(self.uuidAction, command); } }, 3000); } }; module.exports = BlindsItem;