diff --git a/platforms/FHEM.js b/platforms/FHEM.js index a4e35f9..ada3c47 100644 --- a/platforms/FHEM.js +++ b/platforms/FHEM.js @@ -20,17 +20,16 @@ var types = require('HAP-NodeJS/accessories/types.js'); var util = require('util'); -// cached readings from longpoll & query -var FHEM_cached = {}; - - // subscriptions to fhem longpoll evens var FHEM_subscriptions = {}; function FHEM_subscribe(characteristic, inform_id, accessory) { FHEM_subscriptions[inform_id] = { 'characteristic': characteristic, 'accessory': accessory }; - //FHEM_subscriptions[inform_id] = characteristic; } + +// cached readings from longpoll & query +var FHEM_cached = {}; +//var FHEM_internal = {}; function FHEM_update(inform_id, value, no_update) { var subscription = FHEM_subscriptions[inform_id]; @@ -39,6 +38,18 @@ FHEM_update(inform_id, value, no_update) { || FHEM_cached[inform_id] === value ) return; + //if( FHEM_internal['.'+subscription.accessory.device+'-homekitID'] == undefined ) { + // var info = subscription.characteristic.accessoryController.tcpServer.accessoryInfo; + + // if( info.username ) { + // var accessory = subscription.accessory; + // var cmd = '{$defs{'+ accessory.device +'}->{homekitID} = "'+info.username+'" if(defined($defs{'+ accessory.device +'}));;}'; + // //accessory.execute( cmd ); + + // FHEM_internal['.'+accessory.device+'-homekitID'] = info.username; + // } + //} + FHEM_cached[inform_id] = value; //FHEM_cached[inform_id] = { 'value': value, 'timestamp': Date.now() }; console.log(" caching: " + inform_id + ": " + value + " as " + typeof(value) ); @@ -118,14 +129,25 @@ function FHEM_startLongpoll(connection) { continue; if( reading == 'state') { - if( accessory.isWindow ) { + if( accessory.mappings.window ) { var level = 50; if( match = value.match(/^(\d+)/ ) ) level = parseInt( match[1] ); else if( value == 'locked' ) level = 0; - FHEM_update( device+'-level', level ); + FHEM_update( accessory.mappings.window.informId, level ); + continue; + + } else if( accessory.mappings.lock ) { + var lock = 0; + if( value.match( /^locked/ ) ) + lock = 1; + + if( value.match( /uncertain/ ) ) + level = 4; + + FHEM_update( accessory.mappings.lock.informId, lock ); continue; } else if( match = value.match(/dim(\d+)%/ ) ) { @@ -134,7 +156,7 @@ function FHEM_startLongpoll(connection) { FHEM_update( device+'-pct', pct ); } - } else if(reading == accessory.hasRGB) { + } else if(accessory.mappings.rgb && reading == accessory.mappings.rgb.reading) { var hsv = FHEM_rgb2hsv(value); var hue = parseInt( hsv[0] * 360 ); var sat = parseInt( hsv[1] * 100 ); @@ -354,6 +376,9 @@ FHEMPlatform.prototype = { } else if( s.Attributes.model == 'HM-SEC-WIN' ) { accessory = new FHEMAccessory(that.log, that.connection, s); + } else if( s.Attributes.model == 'HM-SEC-KEY' ) { + accessory = new FHEMAccessory(that.log, that.connection, s); + } else if( s.Internals.TYPE == 'PRESENCE' ) { accessory = new FHEMAccessory(that.log, that.connection, s); @@ -396,7 +421,7 @@ FHEMAccessory(log, connection, s) { var match; if( match = s.PossibleSets.match(/[\^ ]pct\b/) ) { - this.mappings.pct = { reading: 'pct', cmd: 'pct', min: 0, max: 100 }; + this.mappings.pct = { reading: 'pct', cmd: 'pct' }; } else if( match = s.PossibleSets.match(/[\^ ]dim\d+%/) ) { s.hasDim = true; s.pctMax = 100; @@ -418,12 +443,12 @@ FHEMAccessory(log, connection, s) { if( s.PossibleSets.match(/[\^ ]rgb\b/) ) { s.isLight = true; - s.hasRGB = 'rgb'; + this.mappings.rgb = { reading: 'rgb', cmd: 'rgb' }; if( s.Internals.TYPE == 'SWAP_0000002200000003' ) - s.hasRGB = '0B-RGBlevel'; + this.mappings.rgb = { reading: '0B-RGBlevel', cmd: 'rgb' }; } else if( s.PossibleSets.match(/[\^ ]RGB\b/) ) { s.isLight = true; - s.hasRGB = 'RGB'; + this.mappings.rgb = { reading: 'RGB', cmd: 'RGB' }; } if( s.Readings['measured-temp'] ) @@ -433,8 +458,11 @@ FHEMAccessory(log, connection, s) { if( s.Readings.volume ) this.mappings.volume = { reading: 'volume', cmd: 'volume' }; - else if( s.Readings.Volume ) - this.mappings.volume = { reading: 'Volume', cmd: 'Volume' }; + else if( s.Readings.Volume ) { + this.mappings.volume = { reading: 'Volume', cmd: 'Volume', nocache: true }; + if( s.Attributes.generateVolumeEvent == 1 ) + delete this.mappings.volume.nocache; + } if( s.Readings.humidity ) this.mappings.humidity = { reading: 'humidity' }; @@ -453,39 +481,48 @@ FHEMAccessory(log, connection, s) { if( genericType == 'switch' ) s.isSwitch = true; + else if( genericType == 'garage' ) + this.mappings.garage = { cmdOpen: 'on', cmdClose: 'off' }; + else if( genericType == 'light' ) s.isLight = true; else if( genericType == 'blind' || s.Attributes.subType == 'blindActuator' ) { - s.isBlind = 'pct'; + delete this.mappings.pct; + this.mappings.blind = { reading: 'pct', cmd: 'pct' }; } else if( genericType == 'window' || s.Attributes.model == 'HM-SEC-WIN' ) { - s.isWindow = 'level'; + this.mappings.window = { reading: 'level', cmd: 'level' }; + + } else if( genericType == 'lock' + || s.Attributes.model == 'HM-SEC-KEY' ) { + this.mappings.lock = { reading: 'lock' }; } else if( genericType == 'thermostat' || s.Attributes.subType == 'thermostat' ) { s.isThermostat = true; } else if( s.Internals.TYPE == 'CUL_FHTTK' ) { - s.isContactSensor = 'Window'; + this.mappings.contact = { reading: 'Window' }; } else if( s.Attributes.subType == 'threeStateSensor' ) { - s.isContactSensor = 'contact'; + this.mappings.contact = { reading: 'contact' }; } else if( s.Internals.TYPE == 'PRESENCE' ) - s.isOccupancySensor = true; + this.mappings.occupancy = { reading: 'state' }; else if( s.Attributes.model == 'fs20di' ) s.isLight = true; if( s.PossibleSets.match(/[\^ ]desired-temp\b/) ) - s.isThermostat = 'desired-temp'; + this.mappings.thermostat = { reading: 'desired-temp', cmd: 'desired-temp' }; else if( s.PossibleSets.match(/[\^ ]desiredTemperature\b/) ) - s.isThermostat = 'desiredTemperature'; + this.mappings.thermostat = { reading: 'desiredTemperature', cmd: 'desiredTemperature' }; else if( s.isThermostat ) { s.isThermostat = false; + delete this.mappings.thermostat; log( s.Internals.NAME + ' is NOT a thermostat. set for target temperature missing' ); } @@ -509,20 +546,26 @@ FHEMAccessory(log, connection, s) { } } - if( s.isBlind ) - log( s.Internals.NAME + ' is blind ['+ s.isBlind +']' ); - else if( s.isWindow ) + if( this.mappings.door ) + log( s.Internals.NAME + ' is door' ); + else if( this.mappings.garage ) + log( s.Internals.NAME + ' is garage' ); + else if( this.mappings.lock ) + log( s.Internals.NAME + ' is lock ['+ this.mappings.lock.reading +']' ); + else if( this.mappings.window ) log( s.Internals.NAME + ' is window' ); - else if( s.isThermostat ) - log( s.Internals.NAME + ' is thermostat ['+ s.isThermostat +']' ); - else if( s.isContactSensor ) - log( s.Internals.NAME + ' is contactsensor [' + s.isContactSensor +']' ); - else if( s.isOccupancySensor ) + else if( this.mappings.blind ) + log( s.Internals.NAME + ' is blind ['+ this.mappings.blind.reading +']' ); + else if( this.mappings.thermostat ) + log( s.Internals.NAME + ' is thermostat ['+ this.mappings.thermostat.reading +']' ); + else if( this.mappings.contact ) + log( s.Internals.NAME + ' is contactsensor [' + this.mappings.contact.reading +']' ); + else if( this.mappings.occupancy ) log( s.Internals.NAME + ' is occupancysensor' ); - else if( s.hasRGB ) - log( s.Internals.NAME + ' has RGB [0-' + s.hasRGB +']'); + else if( this.mappings.rgb ) + log( s.Internals.NAME + ' has RGB [0-' + this.mappings.rgb.reading +']'); else if( this.mappings.pct ) - log( s.Internals.NAME + ' is dimable [0-'+ this.mappings.pct.max +']' ); + log( s.Internals.NAME + ' is dimable ['+ this.mappings.pct.reading +']' ); else if( s.hasDim ) log( s.Internals.NAME + ' is dimable [0-'+ s.pctMax +']' ); else if( s.isLight ) @@ -530,7 +573,7 @@ FHEMAccessory(log, connection, s) { else log( s.Internals.NAME + ' is switchable' ); - if( this.hasOnOff ) + if( this.hasOnOff ) log( s.Internals.NAME + ' has OnOff [' + this.hasOnOff + ']' ); if( this.mappings.hue ) @@ -573,19 +616,13 @@ FHEMAccessory(log, connection, s) { this.hasDim = s.hasDim; this.pctMax = s.pctMax; - this.hasRGB = s.hasRGB; this.isLight = s.isLight; - this.isBlind = s.isBlind; - this.isWindow = s.isWindow; - this.isThermostat = s.isThermostat; - this.isContactSensor = s.isContactSensor; - this.isOccupancySensor = s.isOccupancySensor; - this.isWindow = s.isWindow; + this.isSwitch = s.isSwitch; //log( util.inspect(s.Readings) ); - if( this.isBlind || this.isDoor || this.isWindow || this.isThermostat ) + if( this.mappings.blind || this.mappings.door || this.mappings.garage || this.mappings.window || this.mappings.thermostat ) delete this.mappings.onOff; var that = this; @@ -598,7 +635,8 @@ FHEMAccessory(log, connection, s) { if( value != undefined ) { var inform_id = that.device +'-'+ reading; that.mappings[key].informId = inform_id; - FHEM_cached[inform_id] = value; + if( !that.mappings[key].nocache ) + FHEM_cached[inform_id] = value; } } } ); @@ -612,10 +650,10 @@ FHEM_dim_values = [ 'dim06%', 'dim12%', 'dim18%', 'dim25%', 'dim31%', 'dim37%', FHEMAccessory.prototype = { reading2homekit: function(reading,value) { if( reading == 'hue' ) { - value = Math.round(value * 360 / this.mappings.hue.max); + value = Math.round(value * 360 / this.mappings.hue ? this.mappings.hue.max : 360); } else if( reading == 'sat' ) { - value = Math.round(value * 100 / this.mappings.sat.max); + value = Math.round(value * 100 / this.mappings.sat ? this.mappings.sat.max : 100); } else if( reading == 'pct' ) { value = parseInt( value ); @@ -628,8 +666,6 @@ FHEMAccessory.prototype = { else value = 2; - value = parseInt(value); - } else if(reading == 'motor') { if( value.match(/^opening/)) value = 1; @@ -638,16 +674,12 @@ FHEMAccessory.prototype = { else value = 2; - value = parseInt(value); - } else if( reading == 'transportState' ) { if( value == 'PLAYING' ) value = 1; else value = 0; - value = parseInt(value); - } else if( reading == 'volume' || reading == 'Volume' ) { value = parseInt( value ); @@ -658,15 +690,20 @@ FHEMAccessory.prototype = { else value = 0; - value = parseInt(value); - } else if( reading == 'Window' ) { if( value.match( /^Closed/ ) ) value = 1; else value = 0; - value = parseInt(value); + } else if( reading == 'lock' ) { + if( value.match( /^locked/ ) ) + value = 1; + else + value = 0; + + if( value.match( /uncertain/ ) ) + value = 4; } else if( reading == 'temperature' || reading == 'measured-temp' @@ -695,13 +732,11 @@ FHEMAccessory.prototype = { value = 0; else if( value == '000000' ) value = 0; - else if( value.match( /^[A-D]0$/ ) ) + else if( value.match( /^[A-D]0$/ ) ) // FIXME: should be handled by event_map now value = 0; else value = 1; - value = parseInt( value ); - } return(value); @@ -721,21 +756,14 @@ FHEMAccessory.prototype = { command: function(c,value) { this.log(this.name + " sending command " + c + " with value " + value); - if( c == 'on' ) { - if( this.PossibleSets.match(/[\^ ]play\b/i) ) - cmd = "set " + this.device + " play"; - else if( this.PossibleSets.match(/[\^ ]on\b/) ) - cmd = "set " + this.device + " on"; + if( c == 'identify' ) { + if( this.type == 'HUEDevice' ) + cmd = "set " + this.device + "alert select"; else - this.log(this.name + " Unhandled command! cmd=" + c + ", value=" + value); + cmd = "set " + this.device + " toggle;; sleep 1;; set "+ this.device + " toggle"; - } else if( c == 'off' ) { - if( this.PossibleSets.match(/[\^ ]pause\b/i) ) - cmd = "set " + this.device + " pause"; - else if( this.PossibleSets.match(/[\^ ]off\b/) ) - cmd = "set " + this.device + " off"; - else - this.log(this.device + " Unhandled command! cmd=" + c + ", value=" + value); + } else if( c == 'set' ) { + cmd = "set " + this.device + " " + value; } else if( c == 'volume' ) { cmd = "set " + this.device + " volume " + value; @@ -776,10 +804,7 @@ FHEMAccessory.prototype = { value = FHEM_hsv2rgb( h, s, v ); //this.log( this.name + ' rgb : [' + value + ']' ); - if( this.PossibleSets.match(/[\^ ]RGB\b/) ) - cmd = "set " + this.device + " RGB " + value; - else - cmd = "set " + this.device + " rgb " + value; + cmd = "set " + this.device + " " + this.mappings.rgb.cmd + " " + value; } else if( c == 'hue' ) { value = Math.round(value * this.mappings.hue.max / 360); @@ -790,17 +815,17 @@ FHEMAccessory.prototype = { cmd = "set " + this.device + " sat " + value; } else if( c == 'targetTemperature' ) { - cmd = "set " + this.device + " " + this.isThermostat + " " + value; + cmd = "set " + this.device + " " + this.mappings.thermostat.cmd + " " + value; } else if( c == 'targetPosition' ) { - if( this.isWindow ) { + if( this.mappings.window ) { if( value == 0 ) value = 'lock'; - cmd = "set " + this.device + " level " + value; + cmd = "set " + this.device + " " + this.mappings.window.cmd + " " + value; - } else if( this.isBlind ) - cmd = "set " + this.device + " " + this.isBlind + " " + value; + } else if( this.mappings.blind ) + cmd = "set " + this.device + " " + this.mappings.blind.cmd + " " + value; else this.log(this.name + " Unhandled command! cmd=" + c + ", value=" + value); @@ -851,19 +876,22 @@ FHEMAccessory.prototype = { this.log(" not cached" ); var query_reading = reading; - if( reading == 'hue' && !this.mappings.hue && this.hasRGB ) { - query_reading = this.hasRGB; + if( reading == 'hue' && !this.mappings.hue && this.mappings.rgb ) { + query_reading = this.mappings.rgb.reading; - } else if( reading == 'sat' && !this.mappings.sat && this.hasRGB ) { - query_reading = this.hasRGB; + } else if( reading == 'sat' && !this.mappings.sat && this.mappings.rgb ) { + query_reading = this.mappings.rgb.reading; - } else if( reading == 'bri' && !this.mappings.pct && this.hasRGB ) { - query_reading = this.hasRGB; + } else if( reading == 'bri' && !this.mappings.pct && this.mappings.rgb ) { + query_reading = this.mappings.rgb.reading; } else if( reading == 'pct' && !this.mappings.pct && this.hasDim ) { query_reading = 'state'; - } else if( reading == 'level' && this.isWindow ) { + } else if( reading == 'level' && this.mappings.window ) { + query_reading = 'state'; + + } else if( reading == 'lock' && this.mappings.lock ) { query_reading = 'state'; } @@ -900,17 +928,28 @@ FHEMAccessory.prototype = { else value = 50; - } else if(reading == 'hue' && query_reading == that.hasRGB) { + } else if( reading == 'lock' + && query_reading == 'state') { + + if( value.match( /^locked/ ) ) + value = 1; + else + value = 0; + + if( value.match( /uncertain/ ) ) + value = 4; + + } else if(reading == 'hue' && query_reading == that.mappings.rgb) { //FHEM_update( that.device+'-'+query_reading, value ); value = parseInt( FHEM_rgb2hsv(value)[0] * 360 ); - } else if(reading == 'sat' && query_reading == that.hasRGB) { + } else if(reading == 'sat' && query_reading == that.mappings.rgb) { //FHEM_update( that.device+'-'+query_reading, value ); value = parseInt( FHEM_rgb2hsv(value)[1] * 100 ); - } else if(reading == 'bri' && query_reading == that.hasRGB) { + } else if(reading == 'bri' && query_reading == that.mappings.rgb) { //FHEM_update( that.device+'-'+query_reading, value ); value = parseInt( FHEM_rgb2hsv(value)[2] * 100 ); @@ -969,14 +1008,17 @@ FHEMAccessory.prototype = { onUpdate: null, perms: ["pr"], format: "string", - initialValue: this.serial ? this.serial : "A1S2NASF88EW", + initialValue: this.serial ? this.serial : "", supportEvents: false, supportBonjour: false, manfDescription: "SN", designedMaxLength: 255 },{ cType: types.IDENTIFY_CTYPE, - onUpdate: null, + onUpdate: function(value) { + if( this.mappings.onOff ) + that.command( 'identify' ); + }, perms: ["pw"], format: "bool", initialValue: false, @@ -984,8 +1026,7 @@ FHEMAccessory.prototype = { supportBonjour: false, manfDescription: "Identify Accessory", designedMaxLength: 1 - } - ] + }]; }, controlCharacteristics: function(that) { @@ -1009,7 +1050,7 @@ FHEMAccessory.prototype = { FHEM_subscribe(characteristic, that.mappings.onOff.informId, that); }, onUpdate: function(value) { - that.command( value == 0 ? 'off' : 'on' ); + that.command( 'set', value == 0 ? that.mappings.onOff.cmdOff : that.mappings.onOff.cmdOn ); }, onRead: function(callback) { that.query( that.mappings.onOff.reading, function(state){ callback(state) } ); @@ -1024,7 +1065,7 @@ FHEMAccessory.prototype = { }); } - if( this.mappings.pct && !this.isBlind ) { + if( this.mappings.pct ) { cTypes.push({ cType: types.BRIGHTNESS_CTYPE, onRegister: function(characteristic) { @@ -1053,6 +1094,7 @@ FHEMAccessory.prototype = { cType: types.BRIGHTNESS_CTYPE, onRegister: function(characteristic) { characteristic.eventEnabled = true; + // state is alreadi subscribed from POWER_STATE_CTYPE FHEM_subscribe(characteristic, that.name+'-pct', that); }, onUpdate: function(value) { that.delayed('dim', value); }, @@ -1099,13 +1141,13 @@ FHEMAccessory.prototype = { designedMinStep: 1, unit: "arcdegrees" }); - } else if( this.hasRGB ) { + } else if( this.mappings.rgb ) { cTypes.push({ cType: types.HUE_CTYPE, onRegister: function(characteristic) { characteristic.eventEnabled = true; FHEM_subscribe(characteristic, that.name+'-hue', that); - FHEM_subscribe(characteristic, that.name+'-'+that.hasRGB, that); + FHEM_subscribe(characteristic, that.mappings.rgb.informId, that); }, onUpdate: function(value) { that.command('H-rgb', value); }, onRead: function(callback) { @@ -1208,8 +1250,10 @@ FHEMAccessory.prototype = { cType: types.OUTPUTVOLUME_CTYPE, onUpdate: function(value) { that.delayed('volume', value); }, onRegister: function(characteristic) { - //characteristic.eventEnabled = true; - //FHEM_subscribe(characteristic, that.mappings.volume.informId, that); + if( !that.mappings.volume.nocache ) { + characteristic.eventEnabled = true; + FHEM_subscribe(characteristic, that.mappings.volume.informId, that); + } }, onRead: function(callback) { that.query(that.mappings.volume.reading, function(volume){ @@ -1230,23 +1274,22 @@ FHEMAccessory.prototype = { }); } - if( this.isBlind ) { + if( this.mappings.blind ) { cTypes.push({ cType: types.WINDOW_COVERING_TARGET_POSITION_CTYPE, onUpdate: function(value) { that.delayed('targetPosition', value, 1500); }, //onRegister: function(characteristic) { // characteristic.eventEnabled = true; - // FHEM_subscribe(characteristic, that.name+'-'+that.isBlind, that); + // FHEM_subscribe(characteristic, that.mappings.blind.informId, that); //}, onRead: function(callback) { - that.query(that.isBlind, function(pct){ + that.query(that.mappings.blind.reading, function(pct){ callback(pct); }); }, perms: ["pw","pr","ev"], format: "int", - //initialValue: 100, - initialValue: FHEM_cached[that.device +'-'+ that.isBlind], + initialValue: FHEM_cached[that.mappings.blind.informId], supportEvents: false, supportBonjour: false, manfDescription: "Target Blind Position", @@ -1259,16 +1302,16 @@ FHEMAccessory.prototype = { cType: types.WINDOW_COVERING_CURRENT_POSITION_CTYPE, onRegister: function(characteristic) { characteristic.eventEnabled = true; - FHEM_subscribe(characteristic, that.name+'-'+that.isBlind, that); + FHEM_subscribe(characteristic, that.mappings.blind.informId, that); }, onRead: function(callback) { - that.query(that.isBlind, function(pos){ + that.query(that.mappings.blind.reading, function(pos){ callback(pos); }); }, perms: ["pr","ev"], format: "int", - initialValue: FHEM_cached[that.name+'-'+that.isBlind], + initialValue: FHEM_cached[that.mappings.blind.informId], supportEvents: true, supportBonjour: false, manfDescription: "Current Blind Position", @@ -1304,16 +1347,12 @@ FHEMAccessory.prototype = { }); } - if( this.isWindow ) { + if( this.mappings.window ) { cTypes.push({ cType: types.WINDOW_COVERING_TARGET_POSITION_CTYPE, onUpdate: function(value) { that.delayed('targetPosition', value, 1500); }, - //onRegister: function(characteristic) { - // characteristic.eventEnabled = true; - // FHEM_subscribe(characteristic, that.name+'-'+that.isBlind, that); - //}, onRead: function(callback) { - that.query(that.isWindow, function(level){ + that.query(that.mappings.window.reading, function(level){ callback(level); }); }, @@ -1333,17 +1372,16 @@ FHEMAccessory.prototype = { onRegister: function(characteristic) { characteristic.eventEnabled = true; FHEM_subscribe(characteristic, that.name+'-state', that); - FHEM_subscribe(characteristic, that.name+'-'+that.isWindow, that); + FHEM_subscribe(characteristic, that.mappings.window.informId, that); }, onRead: function(callback) { - that.query(that.isWindow, function(pos){ + that.query(that.mappings.window.reading, function(pos){ callback(pos); }); }, perms: ["pr","ev"], format: "int", - initialValue: 50, - //initialValue: FHEM_cached[that.name+'-'+that.isWindow], + initialValue: FHEM_cached[that.mappings.window.informId], supportEvents: true, supportBonjour: false, manfDescription: "Current Window Position", @@ -1379,23 +1417,75 @@ FHEMAccessory.prototype = { }); } + if( this.mappings.garage ) { + cTypes.push({ + onUpdate: function(value) { + that.command( 'set', value == 0 ? that.mappings.garage.cmdOpen : that.mappings.garage.cmdClose ); + }, + cType: types.TARGET_DOORSTATE_CTYPE, + onRead: function(callback) { + callback(1); + }, + perms: ["pw","pr","ev"], + format: "int", + initialValue: 1, + supportEvents: false, + supportBonjour: false, + manfDescription: "Target GarageDoor Position", + designedMinValue: 0, + designedMaxValue: 1, + designedMinStep: 1, + designedMaxLength: 1 + }); + cTypes.push({ + cType: types.CURRENT_DOOR_STATE_CTYPE, + onRead: function(callback) { + callback(4); + }, + perms: ["pr","ev"], + format: "int", + initialValue: 4, + supportEvents: true, + supportBonjour: false, + manfDescription: "Current GarageDoor State", + designedMinValue: 0, + designedMaxValue: 4, + designedMinStep: 1, + designedMaxLength: 1 + }); + + cTypes.push({ + cType: types.OBSTRUCTION_DETECTED_CTYPE, + onRead: function(callback) { + callback(false); + }, + perms: ["pr","ev"], + format: "bool", + initialValue: 0, + supportEvents: false, + supportBonjour: false, + manfDescription: "Obstruction Detected", + designedMaxLength: 1 + }); + } + //FIXME: parse range and set designedMinValue & designedMaxValue & designedMinStep - if( this.isThermostat ) { + if( this.mappings.thermostat ) { cTypes.push({ cType: types.TARGET_TEMPERATURE_CTYPE, onUpdate: function(value) { that.delayed('targetTemperature', value, 1500); }, onRegister: function(characteristic) { characteristic.eventEnabled = true; - FHEM_subscribe(characteristic, that.name+'-'+that.isThermostat, that); + FHEM_subscribe(characteristic, that.mappings.thermostat.informId, that); }, onRead: function(callback) { - that.query(that.isThermostat, function(temperature){ + that.query(that.mappings.thermostat.reading, function(temperature){ callback(temperature); }); }, perms: ["pw","pr","ev"], format: "float", - initialValue: 20, + initialValue: FHEM_cached[that.mappings.thermostat.informId], supportEvents: false, supportBonjour: false, manfDescription: "Target Temperature", @@ -1442,21 +1532,21 @@ FHEMAccessory.prototype = { }); } - if( this.isContactSensor ) { + if( this.mappings.contact ) { cTypes.push({ cType: types.CONTACT_SENSOR_STATE_CTYPE, onRegister: function(characteristic) { characteristic.eventEnabled = true; - FHEM_subscribe(characteristic, that.name+'-'+that.isContactSensor, that); + FHEM_subscribe(characteristic, that.mappings.contact.informId, that); }, onRead: function(callback) { - that.query(that.isContactSensor, function(state){ + that.query(that.mappings.contact.reading, function(state){ callback(state); }); }, perms: ["pr","ev"], format: "bool", - initialValue: 0, + initialValue: FHEM_cached[that.mappings.contact.informId], supportEvents: false, supportBonjour: false, manfDescription: "Contact State", @@ -1464,21 +1554,21 @@ FHEMAccessory.prototype = { }); } - if( this.isOccupancySensor ) { + if( this.mappings.occupancy ) { cTypes.push({ cType: types.OCCUPANCY_DETECTED_CTYPE, onRegister: function(characteristic) { characteristic.eventEnabled = true; - FHEM_subscribe(characteristic, that.name+'-state', that); + FHEM_subscribe(characteristic, that.mappings.occupancy.informId, that); }, onRead: function(callback) { - that.query('state', function(state){ + that.query(that.mappings.occupancy.reading, function(state){ callback(state); }); }, perms: ["pr","ev"], format: "bool", - initialValue: 0, + initialValue: FHEM_cached[that.mappings.occupancy.informId], supportEvents: false, supportBonjour: false, manfDescription: "Occupancy State", @@ -1541,17 +1631,19 @@ FHEMAccessory.prototype = { return types.SPEAKER_STYPE; } else if( this.isSwitch ) { return types.SWITCH_STYPE; - } else if( this.isBlind ) { - return types.WINDOW_COVERING_STYPE; - } else if( this.isThermostat ) { - return types.THERMOSTAT_STYPE; - } else if( this.isWindow ) { + } else if( this.mappings.garage ) { + return types.GARAGE_DOOR_OPENER_STYPE; + } else if( this.mappings.window ) { return types.WINDOW_STYPE; - } else if( this.isContactSensor ) { + } else if( this.mappings.blind ) { + return types.WINDOW_COVERING_STYPE; + } else if( this.mappings.thermostat ) { + return types.THERMOSTAT_STYPE; + } else if( this.mappings.contact ) { return types.CONTACT_SENSOR_STYPE; - } else if( this.isOccupancySensor ) { + } else if( this.mappings.occupancy ) { return types.OCCUPANCY_SENSOR_STYPE; - } else if( this.isLight || this.mappings.pct || this.mappings.hue || this.hasRGB ) { + } else if( this.isLight || this.mappings.pct || this.mappings.hue || this.mappings.rgb ) { return types.LIGHTBULB_STYPE; } else if( this.mappings.temperature ) { return types.TEMPERATURE_SENSOR_STYPE; @@ -1591,17 +1683,17 @@ function FHEMdebug_handleRequest(request, response){ //console.log( request ); if( request.url == "/cached" ) { - response.write( "home
" ); + response.write( "home

" ); if( FHEM_lastEventTimestamp ) - response.write( "FHEM_lastEventTime: "+ new Date(FHEM_lastEventTimestamp) +"
" ); + response.write( "FHEM_lastEventTime: "+ new Date(FHEM_lastEventTimestamp) +"

" ); response.end( "cached: " + util.inspect(FHEM_cached).replace(/\n/g, '
') ); } else if( request.url == "/subscriptions" ) { - response.write( "home
" ); + response.write( "home

" ); response.end( "subscriptions: " + util.inspect(FHEM_subscriptions, {depth: 4}).replace(/\n/g, '
') ); } else if( request.url == "/persist" ) { - response.write( "home
" ); + response.write( "home

" ); var unique = {}; Object.keys(FHEM_subscriptions).forEach(function(key) { var characteristic = FHEM_subscriptions[key].characteristic;