homebridge-knx
Version:
homebridge shim for KNX home automation.
159 lines (146 loc) • 5.66 kB
JavaScript
/* Sample module - Simple handler for rolling shutter actuator
* This sample shows how additional values can be taken into account.
*
* Like the jalousie/blinds example just with reversed percentage 100% =
*/
/* jshint esversion: 6, strict: true, node: true */
'use strict';
/**
* @type {HandlerPattern}
*/
var HandlerPattern = require('./handlerpattern.js');
var log = require('debug')('GiraAwningActuator');
/**
* @class A custom handler for the GIRA 216100 "Jalousie Aktor" (rolling shutter/blinds actuator)
* @extends HandlerPattern
*/
class GiraAwningActuator extends HandlerPattern {
/*******************************************************************************************************************
* onKNXValueChange is invoked if a Bus value for one of the bound addresses is received
*
*/
onKNXValueChange(field, oldValue, knxValue) {
// value for HomeKit
var newValue;
log('INFO: onKNXValueChange(' + field + ", "+ oldValue + ", "+ knxValue+ ")");
if (field==="TargetPosition") {
// TargetPosition is DPT5.001 Percentage (0..255)
// need to convert to (0..100) first
// Homekit is using %-open, meaning 0% is closed/down
newValue = knxValue*100/255;
if (newValue>this.myAPI.getValue("CurrentPosition")) {
// newValue is higher, awning's moving out
this.myAPI.setValue("PositionState", 1); //
} else if (newValue<this.myAPI.getValue("CurrentPosition")){
// newValue is higher, shutter's moving in
this.myAPI.setValue("PositionState", 0); //
}
this.myAPI.setValue("TargetPosition", newValue);
if (this.timer){
// avoid resetting Target Position through a timer
clearTimeout(this.timer);
this.timer = undefined;
}
this.lastCommand = 'target';
} else if (field==="CurrentPosition") {
// Current Position is sent by the actuator if the Movement has stopped a new postion is reached
// CurrentPosition is DPT5.001 Percentage (0..255)
// need to convert to (0..100) first
// Homekit is using %-open, meaning 0% is closed/down
newValue = knxValue*100/255;
this.myAPI.setValue("CurrentPosition", newValue); // inform homekit
this.myAPI.setValue("PositionState", 2); //stopped
if (this.lastCommand==='move') {
// return to stopped immediately, and set the Target to Current
this.myAPI.setValue("TargetPosition", this.myAPI.getValue("CurrentPosition"));
} else {
if (!this.timeout) {
this.timeout = this.myAPI.getLocalConstant("TimeOutSecs")*1000 || 60000;
}
if (this.timer){
clearTimeout(this.timer); // start a new one
}
this.timer = setTimeout(function() {
log('Idle Timer reached! Assume motion stopped and target position was not used, so we set it to current position');
this.myAPI.setValue("TargetPosition", this.myAPI.getValue("CurrentPosition"));
this.timer = undefined;
}.bind(this), this.timeout );
}
} else if (field==="ShutterMove") {
// this isn't a characteristic, we need this extra object to catch switch use, too
// The actuator is lowering the rolling shutters if a 1 is received, and
// raises on a 0
this.lastCommand = 'move';
switch (knxValue) {
case 0:
this.myAPI.setValue("TargetPosition", 0); // in position, so home shows "closing"
this.myAPI.setValue("PositionState", 0); //up
break;
case 1:
this.myAPI.setValue("TargetPosition", 100); // out position, so home shows "opening"
this.myAPI.setValue("PositionState", 1); //down
break;
} // switch
} //if
} // onBusValueChange
/*******************************************************************************************************************
* onHKValueChange is invoked if HomeKit is changing characteristic values
*
*/
onHKValueChange(field, oldValue, newValue) {
// homekit will only send a TargetPosition value, so we do not care about (non-) potential others
if (field==="TargetPosition") {
log('INFO: onHKValueChange(' + field + ", "+ oldValue + ", "+ newValue + ")");
// update the PositionState characteristic:
// get the last current Position
var lastPos = this.myAPI.getValue("CurrentPosition");
if (newValue>lastPos) {
// newValue is higher, shutter's moving up
this.myAPI.setValue("PositionState", 1); //up
} else if (newValue<lastPos){
// newValue is higher, shutter's moving down
this.myAPI.setValue("PositionState", 0); //down
}
var knxValue = (newValue*255/100);
log('INFO: onHKValueChange after calc (' + knxValue+ ")");
this.myAPI.knxWrite("TargetPosition", knxValue, "DPT5"); // send the new position to the KNX bus
}
} // onHKValueChange
} // class
module.exports= GiraAwningActuator;
/* **********************************************************************************************************************
* The config for that should look like: LocalConstants is now used in this sample
* Reverse keyword is not allowed for custom handlers
*
*
"Services": [{
"ServiceType": "WindowCovering",
"Handler": "GiraAwningActuator",
"ServiceName": "Porch Awning",
"Characteristics": [{
"Type": "TargetPosition",
"Set": "1/2/3",
"Listen": "1/2/4",
"DPT": "DPT5.001"
},
{
"Type": "CurrentPosition",
"Set": "1/3/1",
"Listen": "1/3/2"
},
{
"Type": "PositionState"
}],
"KNXObjects": [{
"Type": "ShutterMove",
"Listen": "1/2/1",
"DPT": "DPT1"
}],
"KNX-ReadRequests": ["1/2/4",
"1/3/2"],
"LocalConstants": {"TimeOutSecs": 60}
}]
*
*
*
*/