From 90e67c8759ec4475202ab1cdcf54b98401b6926e Mon Sep 17 00:00:00 2001 From: Simone Tisa Date: Mon, 17 Apr 2017 17:53:30 +0200 Subject: [PATCH 01/96] adding features: DryContacts, Alarm, PowerMeters, SetTime and more --- index.js | 999 ++++++++++++++++++++++++++++++++++++++++++++---- lib/mhclient.js | 192 +++++++++- 2 files changed, 1101 insertions(+), 90 deletions(-) mode change 100644 => 100755 lib/mhclient.js diff --git a/index.js b/index.js index bb8a9db..e5fae21 100644 --- a/index.js +++ b/index.js @@ -11,7 +11,6 @@ module.exports = function (homebridge) { UUIDGen = homebridge.hap.uuid; - /* Try to map Elgato's outlet custom vars */ LegrandMyHome.CurrentPowerConsumption = function() { Characteristic.call(this, 'Consumption', 'E863F10D-079E-48FF-8F27-9C2605A29F52'); @@ -27,12 +26,99 @@ module.exports = function (homebridge) { }; LegrandMyHome.CurrentPowerConsumption.UUID = 'E863F10D-079E-48FF-8F27-9C2605A29F52'; inherits(LegrandMyHome.CurrentPowerConsumption, Characteristic); + + LegrandMyHome.TotalConsumption = function() { + Characteristic.call(this, 'Energy', 'E863F10C-079E-48FF-8F27-9C2605A29F52'); + this.setProps({ + format: Characteristic.Formats.FLOAT, + unit: "kWh", + maxValue: 100000000000, + minValue: 0, + minStep: 0.001, + perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY] + }); + this.value = this.getDefaultValue(); + }; + LegrandMyHome.TotalConsumption.UUID = 'E863F10C-079E-48FF-8F27-9C2605A29F52'; + inherits(LegrandMyHome.TotalConsumption, Characteristic); + + LegrandMyHome.E863F116 = function() { + Characteristic.call(this, 'ReadTrunk1', 'E863F116-079E-48FF-8F27-9C2605A29F52'); + this.setProps({ + format: Characteristic.Formats.DATA, + perms: [Characteristic.Perms.READ] + }); + this.value = this.getDefaultValue(); + }; + LegrandMyHome.E863F116.UUID = 'E863F116-079E-48FF-8F27-9C2605A29F52'; + inherits(LegrandMyHome.E863F116, Characteristic); + + LegrandMyHome.E863F117 = function() { + Characteristic.call(this, 'ReadTrunk2', 'E863F117-079E-48FF-8F27-9C2605A29F52'); + this.setProps({ + format: Characteristic.Formats.DATA, + perms: [Characteristic.Perms.READ, Characteristic.Perms.WRITE] + }); + this.value = this.getDefaultValue(); + }; + LegrandMyHome.E863F117.UUID = 'E863F117-079E-48FF-8F27-9C2605A29F52'; + inherits(LegrandMyHome.E863F117, Characteristic); + + + LegrandMyHome.E863F11C = function() { + Characteristic.call(this, 'WriteTrunk1', 'E863F11C-079E-48FF-8F27-9C2605A29F52'); + this.setProps({ + format: Characteristic.Formats.DATA, + perms: [Characteristic.Perms.WRITE] + }); + this.value = null; + }; + LegrandMyHome.E863F11C.UUID = 'E863F11C-079E-48FF-8F27-9C2605A29F52'; + inherits(LegrandMyHome.E863F11C, Characteristic); + + LegrandMyHome.E863F121 = function() { + Characteristic.call(this, 'WriteTrunk2', 'E863F121-079E-48FF-8F27-9C2605A29F52'); + this.setProps({ + format: Characteristic.Formats.DATA, + perms: [Characteristic.Perms.WRITE] + }); + this.value = null; + }; + LegrandMyHome.E863F121.UUID = 'E863F121-079E-48FF-8F27-9C2605A29F52'; + inherits(LegrandMyHome.E863F121, Characteristic); + + + LegrandMyHome.PowerMeterService = function(displayName, subtype) { Service.call(this, displayName, '00000001-0000-1777-8000-775D67EC4377', subtype); this.addCharacteristic(LegrandMyHome.CurrentPowerConsumption); + this.addCharacteristic(LegrandMyHome.TotalConsumption); + this.addCharacteristic(Characteristic.ResetFilterIndication); }; inherits(LegrandMyHome.PowerMeterService, Service); + LegrandMyHome.PowerLogging = function(displayName, subtype) { + Service.call(this, displayName, 'E863F007-079E-48FF-8F27-9C2605A29F52', subtype); + /*this.addCharacteristic(LegrandMyHome.E863F116); + this.addCharacteristic(LegrandMyHome.E863F117); + this.addCharacteristic(LegrandMyHome.E863F11C); + this.addCharacteristic(LegrandMyHome.E863F121);*/ + }; + inherits(LegrandMyHome.PowerLogging, Service); + + LegrandMyHome.ControlledLoadService = function(displayName, subtype) { + Service.call(this, displayName, 'D43133F2-9BDE-4731-9FF2-B427189DCB4A', subtype); + this.addCharacteristic(Characteristic.OutletInUse); + this.addCharacteristic(Characteristic.Active); + }; + inherits(LegrandMyHome.ControlledLoadService, Service); + + LegrandMyHome.RainSensorService = function(displayName, subtype) { + Service.call(this, displayName, '9018CDC8-DEF9-49D5-A969-63F8CCAAB1A6', subtype); + this.addCharacteristic(Characteristic.CurrentRelativeHumidity); + }; + inherits(LegrandMyHome.RainSensorService, Service); + process.setMaxListeners(0); homebridge.registerPlatform("homebridge-myhome", "LegrandMyHome", LegrandMyHome); @@ -48,7 +134,7 @@ class LegrandMyHome { this.ready = false; this.devices = []; this.lightBuses = []; - this.controller = new mh.MyHomeClient(config.ipaddress, config.port, config.ownpassword, this); + this.controller = new mh.MyHomeClient(config.ipaddress, config.port, config.ownpassword, config.setclock, this); this.config.devices.forEach(function (accessory) { this.log.info("LegrandMyHome: adds accessory"); accessory.parent = this; @@ -56,13 +142,19 @@ class LegrandMyHome { if (accessory.accessory == 'MHBlind') this.devices.push(new MHBlind(this.log,accessory)) if (accessory.accessory == 'MHBlindAdvanced') this.devices.push(new MHBlindAdvanced(this.log,accessory)) if (accessory.accessory == 'MHOutlet') this.devices.push(new MHRelay(this.log,accessory)) - if (accessory.accessory == 'MHRelayLight') this.devices.push(new MHRelay(this.log,accessory)) + if (accessory.accessory == 'MHTimedRelay') this.devices.push(new MHTimedRelay(this.log,accessory)) + if (accessory.accessory == 'MHRain') this.devices.push(new MHRain(this.log,accessory)) if (accessory.accessory == 'MHDimmer') this.devices.push(new MHDimmer(this.log,accessory)) if (accessory.accessory == 'MHThermostat') this.devices.push(new MHThermostat(this.log,accessory)) if (accessory.accessory == 'MHExternalThermometer') this.devices.push(new MHThermometer(this.log,accessory)) - if (accessory.accessory == 'MHContactSensor') this.devices.push(new MHContactSensor(this.log,accessory)) + + if (accessory.accessory == 'MHDryContact') this.devices.push(new MHDryContact(this.log,accessory)) + if (accessory.accessory == 'MHAux') this.devices.push(new MHAux(this.log,accessory)) + /* if (accessory.accessory == 'MHButton') this.devices.push(new MHButton(this.log,accessory)) */ - /* if (accessory.accessory == 'MHPowerMeter') this.devices.push(new MHPowerMeter(this.log,accessory)) */ + if (accessory.accessory == 'MHPowerMeter') this.devices.push(new MHPowerMeter(this.log,accessory)) + if (accessory.accessory == 'MHAlarm') this.devices.push(new MHAlarm(this.log,accessory)) + if (accessory.accessory == 'MHControlledLoad') this.devices.push(new MHControlledLoad(this.log,accessory)) }.bind(this)); this.log.info("LegrandMyHome for MyHome Gateway at " + config.ipaddress + ":" + config.port); this.controller.start(); @@ -75,19 +167,72 @@ class LegrandMyHome { onConnect() { this.devices.forEach(function (accessory) { if (accessory.thermostatService !== undefined) this.controller.getThermostatStatus(accessory.address); - if (accessory.contactSensorService !== undefined) this.controller.getContactState(accessory.address); - if (accessory.windowCoveringPlusService !== undefined) this.controller.getAdvancedBlindSate(accessory.address); + if (accessory.contactSensorService !== undefined || accessory.dryContactService !== undefined) this.controller.getContactState(accessory.address); + if (accessory.windowCoveringPlusService !== undefined) this.controller.getAdvancedBlindState(accessory.address); + if (accessory.lightBulbService !== undefined && accessory.pul == true) + this.controller.getRelayState(accessory.address); + if (accessory.rainService !== undefined && accessory.pul == true) + this.controller.getRelayState(accessory.address); + if (accessory.alarmService !== undefined) + this.controller.getAlarmState(); }.bind(this)); } onRelay(_address,_onoff) { - this.devices.forEach(function(accessory) { - if (accessory.address == _address && accessory.lightBulbService !== undefined) { - accessory.power = _onoff; - accessory.bri = _onoff * 100; - accessory.lightBulbService.getCharacteristic(Characteristic.On).getValue(null); - } - }.bind(this)); + + var address = _address.split("/"); + if (address.length != 3) return ""; + var a = parseInt(address[1]), pl = parseInt(address[2]); + + if (pl!=0) + this.devices.forEach(function(accessory) { + if (accessory.address == _address && accessory.lightBulbService !== undefined) { + accessory.power = _onoff; + accessory.bri = _onoff * 100; + accessory.lightBulbService.getCharacteristic(Characteristic.On).getValue(null); + } + if (accessory.address == _address && accessory.rainService !== undefined) { + accessory.power = _onoff; + accessory.rainService.getCharacteristic(Characteristic.CurrentRelativeHumidity).getValue(null); + } + if (accessory.address == _address && accessory.OutletService !== undefined) { + accessory.power = _onoff; + accessory.OutletService.getCharacteristic(Characteristic.On).getValue(null); + } + }.bind(this)); + else + if (a==0) + this.devices.forEach(function(accessory) { + if (accessory.lightBulbService !== undefined && accessory.pul == false) { + accessory.power = _onoff; + accessory.bri = _onoff * 100; + accessory.lightBulbService.getCharacteristic(Characteristic.On).getValue(null); + } + if (accessory.address == _address && accessory.rainService !== undefined) { + accessory.power = _onoff; + accessory.rainService.getCharacteristic(Characteristic.CurrentRelativeHumidity).getValue(null); + } + if (accessory.address == _address && accessory.OutletService !== undefined) { + accessory.power = _onoff; + accessory.OutletService.getCharacteristic(Characteristic.On).getValue(null); + } + }.bind(this)); + else + this.devices.forEach(function(accessory) { + if (accessory.ambient == a && accessory.lightBulbService !== undefined && accessory.pul == false) { + accessory.power = _onoff; + accessory.bri = _onoff * 100; + accessory.lightBulbService.getCharacteristic(Characteristic.On).getValue(null); + } + if (accessory.address == _address && accessory.rainService !== undefined) { + accessory.power = _onoff; + accessory.rainService.getCharacteristic(Characteristic.CurrentRelativeHumidity).getValue(null); + } + if (accessory.address == _address && accessory.OutletService !== undefined) { + accessory.power = _onoff; + accessory.OutletService.getCharacteristic(Characteristic.On).getValue(null); + } + }.bind(this)); } onContactSensor(_address,_state) { @@ -98,39 +243,332 @@ class LegrandMyHome { } }.bind(this)); } + + onDryContact(_address,_state) { + this.devices.forEach(function(accessory) { + if (accessory.address == _address && accessory.dryContactService !== undefined) { + accessory.state = _state; + switch (accessory.type) { + case 'Contact': accessory.dryContactService.getCharacteristic(Characteristic.ContactSensorState).getValue(null); + break; + case 'Leak': accessory.dryContactService.getCharacteristic(Characteristic.LeakDetected).getValue(null); + break; + case 'Motion': accessory.dryContactService.getCharacteristic(Characteristic.MotionDetected).getValue(null); + break; + default: accessory.dryContactService.getCharacteristic(Characteristic.ContactSensorState).getValue(null); + break; + } + } + }.bind(this)); + } + + onAUX(_address,_state) { + this.devices.forEach(function(accessory) { + if (accessory.address == _address && accessory.AUXService !== undefined) { + accessory.state = _state; + switch (accessory.type) { + case 'Contact': accessory.AUXService.getCharacteristic(Characteristic.ContactSensorState).getValue(null); + break; + case 'Leak': accessory.AUXService.getCharacteristic(Characteristic.LeakDetected).getValue(null); + break; + case 'Motion': accessory.AUXService.getCharacteristic(Characteristic.MotionDetected).getValue(null); + break; + case 'Gas': accessory.AUXService.getCharacteristic(Characteristic.CarbonMonoxideDetected).getValue(null); + break; + default: accessory.AUXService.getCharacteristic(Characteristic.ContactSensorState).getValue(null); + break; + } + } + }.bind(this)); + } onDimmer(_address,_level) { + var address = _address.split("/"); + if (address.length != 3) return ""; + var a = parseInt(address[1]), pl = parseInt(address[2]); + + if (pl!=0) + this.devices.forEach(function(accessory) { + if (accessory.address == _address && accessory.lightBulbService !== undefined) { + accessory.power = (_level > 0) ? 1 : 0; + accessory.bri = _level; + accessory.lightBulbService.getCharacteristic(Characteristic.On).getValue(null); + accessory.lightBulbService.getCharacteristic(Characteristic.Brightness).getValue(null); + } + }.bind(this)); + else + if (a==0) + this.devices.forEach(function(accessory) { + if (accessory.lightBulbService !== undefined && accessory.pul == false) { + accessory.power = (_level > 0) ? 1 : 0; + accessory.bri = _level; + accessory.lightBulbService.getCharacteristic(Characteristic.On).getValue(null); + accessory.lightBulbService.getCharacteristic(Characteristic.Brightness).getValue(null); + } + }.bind(this)); + else + this.devices.forEach(function(accessory) { + if (accessory.ambient == a && accessory.lightBulbService !== undefined && accessory.pul == false) { + accessory.power = (_level > 0) ? 1 : 0; + accessory.bri = _level; + accessory.lightBulbService.getCharacteristic(Characteristic.On).getValue(null); + accessory.lightBulbService.getCharacteristic(Characteristic.Brightness).getValue(null); + } + }.bind(this)); + } + + onPowerMeter(_value) { this.devices.forEach(function(accessory) { - if (accessory.address == _address && accessory.lightBulbService !== undefined) { - accessory.power = (_level > 0) ? 1 : 0; - accessory.bri = _level; - accessory.lightBulbService.getCharacteristic(Characteristic.On).getValue(null); + if (accessory.powerMeterService !== undefined) { + accessory.value = _value; + accessory.totalenergy = accessory.totalenergy + _value * accessory.refresh / 3600 / 1000; + accessory.powerMeterService.getCharacteristic(LegrandMyHome.CurrentPowerConsumption).getValue(null); + accessory.powerMeterService.getCharacteristic(LegrandMyHome.TotalConsumption).getValue(null); } }.bind(this)); } - onSimpleBlind(_address,_value) { + onAlarm(_state) { this.devices.forEach(function(accessory) { - if (accessory.address == _address && accessory.windowCoveringService !== undefined) { - switch (_value) { - case 0: - accessory.state = Characteristic.PositionState.STOPPED; - accessory.evaluatePosition(); - break; - case 1: - accessory.state = Characteristic.PositionState.INCREASING; - accessory.evaluatePosition(); - break; - case 2: - accessory.state = Characteristic.PositionState.DECREASING; - accessory.evaluatePosition(); - break; + if (accessory.alarmService !== undefined) { + if (_state==3) + { + accessory.active = false; + accessory.triggered = false; } - accessory.windowCoveringService.getCharacteristic(Characteristic.PositionState).getValue(null); - accessory.windowCoveringService.getCharacteristic(Characteristic.CurrentPosition).getValue(null); - accessory.windowCoveringService.getCharacteristic(Characteristic.TargetPosition).getValue(null); + else + if (_state==1) + accessory.active = true; + if (_state == 4) + accessory.triggered = true; + if ((accessory.active==true && _state!=1)) + { + accessory.state = _state; + accessory.alarmService.getCharacteristic(Characteristic.SecuritySystemCurrentState).getValue(null); + } + if ((accessory.active==false && _state!=4)) + { + accessory.state = _state; + accessory.alarmService.getCharacteristic(Characteristic.SecuritySystemCurrentState).getValue(null); + } + + if (_state != 4) + { + accessory.target = _state; + accessory.alarmService.getCharacteristic(Characteristic.SecuritySystemTargetState).getValue(null); + } + } + }.bind(this)); + } + + onAlarmFault(_state){ + this.devices.forEach(function(accessory) { + if (accessory.alarmService !== undefined) { + accessory.fault = _state; + accessory.alarmService.getCharacteristic(Characteristic.StatusFault).getValue(null); + } + }.bind(this)); + + } + + onAlarmTampered(_state){ + this.devices.forEach(function(accessory) { + if (accessory.alarmService !== undefined) { + accessory.tampered = _state; + accessory.alarmService.getCharacteristic(Characteristic.StatusTampered).getValue(null); } }.bind(this)); + + } + + onZoneActive(_zone, _state) + { + this.devices.forEach(function(accessory) { + if (accessory.alarmService !== undefined) { + accessory.zone[_zone] = _state; + if (accessory.zone[0] == true && + accessory.zone[1] == true && + accessory.zone[2] == true && + accessory.zone[3] == true && + accessory.zone[4] == false && + accessory.zone[5] == false && + accessory.zone[6] == false && + accessory.zone[7] == false && + accessory.active == true && + accessory.triggered == false) + { + accessory.state = Characteristic.SecuritySystemCurrentState.AWAY_ARM; + accessory.target = Characteristic.SecuritySystemTargetState.AWAY_ARM; + accessory.alarmService.getCharacteristic(Characteristic.SecuritySystemCurrentState).getValue(null); + accessory.alarmService.getCharacteristic(Characteristic.SecuritySystemTargetState).getValue(null); + } + + else + if (accessory.zone[0] == true && + accessory.zone[1] == false && + accessory.zone[2] == true && + accessory.zone[3] == false && + accessory.zone[4] == false && + accessory.zone[5] == false && + accessory.zone[6] == false && + accessory.zone[7] == false && + accessory.active == true && + accessory.triggered == false) + { + accessory.state = Characteristic.SecuritySystemCurrentState.NIGHT_ARM; + accessory.target = Characteristic.SecuritySystemTargetState.NIGHT_ARM; + accessory.alarmService.getCharacteristic(Characteristic.SecuritySystemCurrentState).getValue(null); + accessory.alarmService.getCharacteristic(Characteristic.SecuritySystemTargetState).getValue(null); + } + else + if (accessory.active == true && accessory.triggered == false) + { + accessory.state = Characteristic.SecuritySystemCurrentState.STAY_ARM; + accessory.target = Characteristic.SecuritySystemTargetState.STAY_ARM; + accessory.alarmService.getCharacteristic(Characteristic.SecuritySystemCurrentState).getValue(null); + accessory.alarmService.getCharacteristic(Characteristic.SecuritySystemTargetState).getValue(null); + } + } + }.bind(this)); + } + + onAlarmLowBattery(_state){ + this.devices.forEach(function(accessory) { + if (accessory.alarmBatteryService !== undefined) { + accessory.lowbattery = _state; + accessory.batterycharging = !_state; + if (_state==0) + accessory.batterylevel = 100; + else + accessory.batterylevel = 0; + accessory.alarmBatteryService.getCharacteristic(Characteristic.StatusLowBattery).getValue(null); + accessory.alarmBatteryService.getCharacteristic(Characteristic.BatteryLevel).getValue(null); + accessory.alarmBatteryService.getCharacteristic(Characteristic.ChargingState).getValue(null); + } + }.bind(this)); + + } + + onControlledLoad(_address,_value){ + this.devices.forEach(function(accessory) { + if (accessory.controlledLoad !== undefined) + { + if (accessory.address == _address) + { + switch (_value){ + case 0: + accessory.enabled=false; + accessory.controlledLoad.getCharacteristic(Characteristic.OutletInUse).getValue(null); + break; + case 1: + accessory.enabled=true; + accessory.controlledLoad.getCharacteristic(Characteristic.OutletInUse).getValue(null); + break; + case 2: + accessory.forced=1; + accessory.controlledLoad.getCharacteristic(Characteristic.Active).getValue(null); + break; + case 3: + accessory.forced=0; + accessory.controlledLoad.getCharacteristic(Characteristic.Active).getValue(null); + break; + } + } + } + }.bind(this)); + } + + onSimpleBlind(_address,_value) { + var address = _address.split("/"); + if (address.length != 3) return ""; + var a = parseInt(address[1]), pl = parseInt(address[2]); + + if (pl!=0) + this.devices.forEach(function(accessory) { + if (accessory.address == _address && accessory.windowCoveringService !== undefined) { + switch (_value) { + case 0: + accessory.state = Characteristic.PositionState.STOPPED; + accessory.evaluatePosition(); + break; + case 1: + if (accessory.invert == false) + accessory.state = Characteristic.PositionState.INCREASING; + else + accessory.state = Characteristic.PositionState.DECREASING; + accessory.evaluatePosition(); + break; + case 2: + + if (accessory.invert == false) + accessory.state = Characteristic.PositionState.DECREASING; + else + accessory.state = Characteristic.PositionState.INCREASING; + accessory.evaluatePosition(); + break; + } + accessory.windowCoveringService.getCharacteristic(Characteristic.PositionState).getValue(null); + accessory.windowCoveringService.getCharacteristic(Characteristic.CurrentPosition).getValue(null); + accessory.windowCoveringService.getCharacteristic(Characteristic.TargetPosition).getValue(null); + } + }.bind(this)); + else + if (a==0) + this.devices.forEach(function(accessory) { + if (accessory.windowCoveringService !== undefined && accessory.pul == false) { + switch (_value) { + case 0: + accessory.state = Characteristic.PositionState.STOPPED; + accessory.evaluatePosition(); + break; + case 1: + if (accessory.invert == false) + accessory.state = Characteristic.PositionState.INCREASING; + else + accessory.state = Characteristic.PositionState.DECREASING; + accessory.evaluatePosition(); + break; + case 2: + if (accessory.invert == false) + accessory.state = Characteristic.PositionState.DECREASING; + else + accessory.state = Characteristic.PositionState.INCREASING; + accessory.evaluatePosition(); + break; + } + accessory.windowCoveringService.getCharacteristic(Characteristic.PositionState).getValue(null); + accessory.windowCoveringService.getCharacteristic(Characteristic.CurrentPosition).getValue(null); + accessory.windowCoveringService.getCharacteristic(Characteristic.TargetPosition).getValue(null); + } + }.bind(this)); + else + this.devices.forEach(function(accessory) { + if (accessory.ambient == a && accessory.windowCoveringService !== undefined && accessory.pul == false) { + switch (_value) { + case 0: + accessory.state = Characteristic.PositionState.STOPPED; + accessory.evaluatePosition(); + break; + case 1: + if (accessory.invert == false) + accessory.state = Characteristic.PositionState.INCREASING; + else + accessory.state = Characteristic.PositionState.DECREASING; + accessory.evaluatePosition(); + break; + case 2: + if (accessory.invert == false) + accessory.state = Characteristic.PositionState.DECREASING; + else + accessory.state = Characteristic.PositionState.INCREASING; + accessory.evaluatePosition(); + break; + } + accessory.windowCoveringService.getCharacteristic(Characteristic.PositionState).getValue(null); + accessory.windowCoveringService.getCharacteristic(Characteristic.CurrentPosition).getValue(null); + accessory.windowCoveringService.getCharacteristic(Characteristic.TargetPosition).getValue(null); + } + }.bind(this)); } onAdvancedBlind(_address,_action,_position) { @@ -219,7 +657,7 @@ class MHRelay { this.name = config.name; this.address = config.address; this.groups = config.groups || []; /* TODO */ - this.pul = false; /* TODO */ + this.pul = config.pul || false; this.displayName = config.name; this.UUID = UUIDGen.generate(sprintf("relay-%s",config.address)); this.log = log; @@ -229,6 +667,11 @@ class MHRelay { this.hue = 0; this.log.info(sprintf("LegrandMyHome::MHRelay create object: %s", this.address)); this.mh.addLightBusDevice(this.address); + + var address = this.address.split("/"); + this.bus = parseInt(address[0]); + this.ambient = parseInt(address[1]); + this.pl = parseInt(address[2]); } getServices() { @@ -239,7 +682,7 @@ class MHRelay { .setCharacteristic(Characteristic.SerialNumber, "Address " + this.address); switch (this.config.accessory) { - case 'MHRelayOutlet': + case 'MHOutlet': this.lightBulbService = new Service.Outlet(this.name); break; default: @@ -247,6 +690,7 @@ class MHRelay { break; } + this.lightBulbService.getCharacteristic(Characteristic.On) .on('set', (level, callback) => { this.log.debug(sprintf("setPower %s = %s",this.address, level)); @@ -269,10 +713,128 @@ class MHRelay { this.log.debug(sprintf("getPower %s = %s",this.address, this.power)); callback(null, this.power); }); + return [service, this.lightBulbService]; } } +class MHTimedRelay { + constructor(log, config) { + this.config = config || {}; + this.mh = config.parent.controller; + this.name = config.name; + this.address = config.address; + this.groups = config.groups || []; /* TODO */ + this.pul = config.pul || false; + this.displayName = config.name; + this.UUID = UUIDGen.generate(sprintf("timedrelay-%s",config.address)); + this.log = log; + this.power = false; + this.timer = config.timer || 1; + this.log.info(sprintf("LegrandMyHome::MHTimedRelay create object: %s", this.address)); + this.mh.addLightBusDevice(this.address); + + var address = this.address.split("/"); + this.bus = parseInt(address[0]); + this.ambient = parseInt(address[1]); + this.pl = parseInt(address[2]); + } + + getServices() { + var service = new Service.AccessoryInformation(); + service.setCharacteristic(Characteristic.Name, this.name) + .setCharacteristic(Characteristic.Manufacturer, "Legrand MyHome") + .setCharacteristic(Characteristic.Model, "TimedRelay") + .setCharacteristic(Characteristic.SerialNumber, "Address " + this.address); + + + this.OutletService = new Service.Outlet(this.name); + this.OutletService.addCharacteristic(Characteristic.LockManagementAutoSecurityTimeout); + this.OutletService.getCharacteristic(Characteristic.LockManagementAutoSecurityTimeout) + .setProps({ + format: Characteristic.Formats.UINT32, + unit: Characteristic.Units.SECONDS, + maxValue: 3540, + minValue: 0, + minStep: 60, + perms: [Characteristic.Perms.READ, Characteristic.Perms.WRITE, Characteristic.Perms.NOTIFY] + }); + this.OutletService.getCharacteristic(Characteristic.On) + .on('set', (_value, callback) => { + //this.log.debug(sprintf("setPower %s = %s",this.address, level)); + this.power = _value; + + /* Custom frame support */ + if (this.power && this.timer !=0) + { + var address = this.mh._slashesToAddress(this.address); + this.mh.send(sprintf("*#1*%s*#2*0*%d*0##",address,this.timer/60)); + } + else + { + this.mh.relayCommand(this.address,this.power) + } + callback(null); + }) + .on('get', (callback) => { + this.log.debug(sprintf("getPower %s = %s",this.address, this.power)); + callback(null, this.power); + }); + this.OutletService.getCharacteristic(Characteristic.LockManagementAutoSecurityTimeout) + .on('set', (time, callback) => { + this.timer = time; + callback(null); + }) + .on('get', (callback) => { + this.log.debug(sprintf("getPower %s = %s",this.address, this.power)); + callback(null, this.timer); + }); + + + return [service, this.OutletService]; + } +} + +class MHRain { + constructor(log, config) { + this.config = config || {}; + this.mh = config.parent.controller; + this.name = config.name; + this.address = config.address; + this.groups = config.groups || []; /* TODO */ + this.pul = config.pul || false; + this.displayName = config.name; + this.UUID = UUIDGen.generate(sprintf("relay-%s",config.address)); + this.log = log; + this.power = 0; + this.log.info(sprintf("LegrandMyHome::MHRain create object: %s", this.address)); + this.mh.addLightBusDevice(this.address); + + var address = this.address.split("/"); + this.bus = parseInt(address[0]); + this.ambient = parseInt(address[1]); + this.pl = parseInt(address[2]); + } + + getServices() { + var service = new Service.AccessoryInformation(); + service.setCharacteristic(Characteristic.Name, this.name) + .setCharacteristic(Characteristic.Manufacturer, "Legrand MyHome") + .setCharacteristic(Characteristic.Model, "Relay") + .setCharacteristic(Characteristic.SerialNumber, "Address " + this.address); + + + this.rainService = new LegrandMyHome.RainSensorService(this.name); + this.rainService.getCharacteristic(Characteristic.CurrentRelativeHumidity) + .on('get', (callback) => { + //this.log.debug(sprintf("getPower %s = %s",this.address, this.power)); + callback(null, 100 - this.power * 100); + }); + + return [service, this.rainService]; + } +} + class MHBlind { constructor(log, config) { this.config = config || {}; @@ -280,11 +842,12 @@ class MHBlind { this.name = config.name; this.address = config.address; this.groups = config.groups || []; /* TODO */ - this.pul = false; /* TODO */ + this.pul = config.pul || false; this.displayName = config.name; this.time = config.time || 0; this.UUID = UUIDGen.generate(sprintf("blind-%s",config.address)); this.log = log; + this.invert = config.invert || false; this.runningStartTime = -1; this.runningDirection = Characteristic.PositionState.STOPPED; @@ -294,16 +857,21 @@ class MHBlind { this.startDelayMs = config.startDelayMs || 0; /* Start delay of the automation and MH relay */ this.timeAdjust = config.timeAdjust || 5; /* Percent error, F411 is a bit buggy */ this.log.info(sprintf("LegrandMyHome::MHBlind create object: %s", this.address)); + + var address = this.address.split("/"); + this.bus = parseInt(address[0]); + this.ambient = parseInt(address[1]); + this.pl = parseInt(address[2]); } evaluatePosition() { - if (this.runningDirection == Characteristic.PositionState.STOPPED && this.currentPosition != Characteristic.PositionState.STOPPED) { + if (this.runningDirection == Characteristic.PositionState.STOPPED && this.state != Characteristic.PositionState.STOPPED) { this.runningStartTime = new Date(); this.runningDirection = this.state; this.log.debug(sprintf("Starting position is %d", this.currentPosition)) } else { if (this.runningDirection != Characteristic.PositionState.STOPPED && this.state == Characteristic.PositionState.STOPPED) { - if (this.runningDirection == Characteristic.PositionState.INCREASING) { + if (this.runningDirection == Characteristic.PositionState.INCREASING) { this.currentPosition = Math.min(100,this.currentPosition + (100 / (this.time*1000) * (((new Date())-this.runningStartTime+this.startDelayMs)*(1+this.timeAdjust/100)))) } else { this.currentPosition = Math.max(0,this.currentPosition - (100 / (this.time*1000) * (((new Date())-this.runningStartTime+this.startDelayMs)*(1+this.timeAdjust/100)))) @@ -405,7 +973,7 @@ class MHBlindAdvanced { this.windowCoveringPlusService.getCharacteristic(Characteristic.PositionState) .on('get', (callback) => { - this.log.info(sprintf("getPositionState %s = %s",this.address, this.state)); + this.log.debug(sprintf("getPositionState %s = %s",this.address, this.state)); callback(null, this.state); }); @@ -445,7 +1013,7 @@ class MHDimmer { this.name = config.name; this.address = config.address; this.groups = config.groups || []; /* TODO */ - this.pul = false; /* TODO */ + this.pul = config.pul || false; this.displayName = config.name; this.UUID = UUIDGen.generate(sprintf("dimmer-%s",config.address)); this.log = log; @@ -455,6 +1023,11 @@ class MHDimmer { this.sat = 0; this.hue = 0; this.log.info(sprintf("LegrandMyHome::MHRelay create object: %s", this.address)); + + var address = this.address.split("/"); + this.bus = parseInt(address[0]); + this.ambient = parseInt(address[1]); + this.pl = parseInt(address[2]); } getServices() { @@ -490,7 +1063,7 @@ class MHDimmer { callback(null); }) .on('get', (callback) => { - this.log(sprintf("getBrightness %s = %d",this.address, this.bri)); + this.log.debug(sprintf("getBrightness %s = %d",this.address, this.bri)); callback(null, this.bri); }); return [service, this.lightBulbService]; @@ -607,100 +1180,376 @@ class MHThermometer { } } -class MHContactSensor { +class MHPowerMeter { constructor(log, config) { this.config = config || {}; this.mh = config.parent.controller; this.name = config.name; - this.address = config.address; this.displayName = config.name; - this.UUID = UUIDGen.generate(sprintf("contactsensor-%s",config.address)); + this.UUID = UUIDGen.generate(sprintf("powermeter-%s",config.address)); this.log = log; + this.refresh = config.refresh || 15; - this.state = false; - this.log.info(sprintf("LegrandMyHome::MHContactSensor create object: %s", this.address)); + this.value = 0; + this.totalenergy = 0; + this.log.info(sprintf("LegrandMyHome::MHPowerMeter create object")); + setInterval(function(){ + this.mh.getPower(); + }.bind(this), this.refresh * 1000); } + identify(callback) { + this.log("Identify requested!"); + callback(); // success + } + getServices() { var service = new Service.AccessoryInformation(); service.setCharacteristic(Characteristic.Name, this.name) .setCharacteristic(Characteristic.Manufacturer, "Legrand MyHome") - .setCharacteristic(Characteristic.Model, "Contact Sensor") + .setCharacteristic(Characteristic.Model, "Power Meter") .setCharacteristic(Characteristic.SerialNumber, "Address " + this.address); - this.contactSensorService = new Service.ContactSensor(this.name); - this.contactSensorService.getCharacteristic(Characteristic.ContactSensorState) + this.powerMeterService = new LegrandMyHome.PowerMeterService(this.name); + this.powerMeterService.getCharacteristic(LegrandMyHome.CurrentPowerConsumption) .on('get', (callback) => { - this.log.debug(sprintf("getContactSensorState %s = %s",this.address, this.state)); - callback(null, this.state); + this.log.debug(sprintf("getConsumptio = %s",this.value)); + callback(null, this.value); + }); + this.powerMeterService.getCharacteristic(LegrandMyHome.TotalConsumption) + .on('get', (callback) => { + this.log.debug(sprintf("getConsumptio = %f",this.totalenergy)); + callback(null, this.totalenergy); + }); + this.powerMeterService.getCharacteristic(Characteristic.ResetFilterIndication) + .on('set', (value, callback) => { + this.totalenergy = 0; + callback(null); + }); + this.powerLoggingService = new LegrandMyHome.PowerLogging(this.name); + /*this.powerLoggingService.getCharacteristic(LegrandMyHome.E863F116) + .on('get', (callback) => { + callback(null, null); + }); + this.powerLoggingService.getCharacteristic(LegrandMyHome.E863F117) + .on('get', (callback) => { + callback(null, null); + }); + this.powerLoggingService.getCharacteristic(LegrandMyHome.E863F11C) + .on('get', (callback) => { + callback(null, null); }); + this.powerLoggingService.getCharacteristic(LegrandMyHome.E863F121) + .on('get', (callback) => { + callback(null, null); + });*/ - return [service, this.contactSensorService]; + return [service, this.powerMeterService, this.powerLoggingService]; } } -class MHPowerMeter { +class MHButton { constructor(log, config) { this.config = config || {}; this.mh = config.parent.controller; this.name = config.name; this.address = config.address; this.displayName = config.name; - this.UUID = UUIDGen.generate(sprintf("powermeter-%s",config.address)); + this.UUID = UUIDGen.generate(sprintf("button-%s",config.address)); this.log = log; this.value = 0; - this.log.info(sprintf("LegrandMyHome::MHPowerMeter create object: %s", this.address)); + this.log.info(sprintf("LegrandMyHome::MHButton (CEN/CEN+) create object: %s", this.address)); } getServices() { var service = new Service.AccessoryInformation(); service.setCharacteristic(Characteristic.Name, this.name) .setCharacteristic(Characteristic.Manufacturer, "Legrand MyHome") - .setCharacteristic(Characteristic.Model, "Power Meter") + .setCharacteristic(Characteristic.Model, "CEN/CEN+") .setCharacteristic(Characteristic.SerialNumber, "Address " + this.address); - this.powerMeterService = new LegrandMyHome.PowerMeterService(this.name); - this.powerMeterService.getCharacteristic(LegrandMyHome.CurrentPowerConsumption) + this.statelessSwitch = new Service.Switch(this.name); + this.statelessSwitch.getCharacteristic(Characteristic.On) + .on('set', (value,callback) => { + this.log.debug(sprintf("setOn %s = %s",this.address, value)); + callback(null); + }) .on('get', (callback) => { - this.log.info(sprintf("getConsumption %s = %s",this.address, this.state)); - callback(null, this.value); + this.log.debug(sprintf("getOn %s",this.address)); + callback(null,0); }); - return [service, this.powerMeterService]; + return [service, this.statelessSwitch]; } + } -class MHButton { + +class MHDryContact { constructor(log, config) { this.config = config || {}; this.mh = config.parent.controller; this.name = config.name; this.address = config.address; this.displayName = config.name; - this.UUID = UUIDGen.generate(sprintf("button-%s",config.address)); + this.UUID = UUIDGen.generate(sprintf("drycontact-%s",config.address)); this.log = log; + this.type = config.type; - this.value = 0; - this.log.info(sprintf("LegrandMyHome::MHButton (CEN/CEN+) create object: %s", this.address)); + this.state = config.state || false; + this.log.info(sprintf("LegrandMyHome::MHDryContact create object: %s", this.address)); } getServices() { var service = new Service.AccessoryInformation(); service.setCharacteristic(Characteristic.Name, this.name) .setCharacteristic(Characteristic.Manufacturer, "Legrand MyHome") - .setCharacteristic(Characteristic.Model, "CEN/CEN+") + .setCharacteristic(Characteristic.Model, "Dry-contact Sensor") .setCharacteristic(Characteristic.SerialNumber, "Address " + this.address); - this.statelessSwitch = new Service.Switch(this.name); - this.statelessSwitch.getCharacteristic(Characteristic.On) + switch (this.type) { + case 'Contact': + this.dryContactService = new Service.ContactSensor(this.name); + this.dryContactService.getCharacteristic(Characteristic.ContactSensorState) + .on('get', (callback) => { + this.log.debug(sprintf("getContactSensorState %s = %s",this.address, this.state)); + callback(null, this.state); + }); + break; + case 'Leak': + this.dryContactService = new Service.LeakSensor(this.name); + this.dryContactService.getCharacteristic(Characteristic.LeakDetected) + .on('get', (callback) => { + this.log.debug(sprintf("getLeakSensorState %s = %s",this.address, this.state)); + callback(null, this.state); + }); + break; + case 'Motion': + this.dryContactService = new Service.MotionSensor(this.name); + this.dryContactService.getCharacteristic(Characteristic.MotionDetected) + .on('get', (callback) => { + this.log.debug(sprintf("getMotionSensorState %s = %s",this.address, this.state)); + callback(null, this.state); + }); + break; + default: + this.dryContactService = new Service.ContactSensor(this.name); + this.dryContactService.getCharacteristic(Characteristic.ContactSensorState) + .on('get', (callback) => { + this.log.debug(sprintf("getContactSensorState %s = %s",this.address, this.state)); + callback(null, this.state); + }); + break; + } + + return [service, this.dryContactService]; + } +} + +class MHAux { + constructor(log, config) { + this.config = config || {}; + this.mh = config.parent.controller; + this.name = config.name; + this.address = config.address; + this.displayName = config.name; + this.UUID = UUIDGen.generate(sprintf("aux-%s",config.address)); + this.log = log; + this.type = config.type; + + this.state = false; + this.log.info(sprintf("LegrandMyHome::MHAux create object: %s", this.address)); + } + + getServices() { + var service = new Service.AccessoryInformation(); + service.setCharacteristic(Characteristic.Name, this.name) + .setCharacteristic(Characteristic.Manufacturer, "Legrand MyHome") + .setCharacteristic(Characteristic.Model, "AUX") + .setCharacteristic(Characteristic.SerialNumber, "Address " + this.address); + + switch (this.type) { + case 'Contact': + this.AUXService = new Service.ContactSensor(this.name); + this.AUXService.getCharacteristic(Characteristic.ContactSensorState) + .on('get', (callback) => { + this.log.debug(sprintf("getContactSensorState %s = %s",this.address, this.state)); + callback(null, this.state); + }); + break; + case 'Leak': + this.AUXService = new Service.LeakSensor(this.name); + this.AUXService.getCharacteristic(Characteristic.LeakDetected) + .on('get', (callback) => { + this.log.debug(sprintf("getLeakSensorState %s = %s",this.address, this.state)); + callback(null, this.state); + }); + break; + case 'Motion': + this.AUXService = new Service.MotionSensor(this.name); + this.AUXService.getCharacteristic(Characteristic.MotionDetected) + .on('get', (callback) => { + this.log.debug(sprintf("getMotionSensorState %s = %s",this.address, this.state)); + callback(null, this.state); + }); + break; + case 'Gas': + this.AUXService = new Service.CarbonMonoxideSensor(this.name); + this.AUXService.getCharacteristic(Characteristic.CarbonMonoxideDetected) + .on('get', (callback) => { + this.log.debug(sprintf("getGasSensorState %s = %s",this.address, this.state)); + callback(null, this.state); + }); + break; + default: + this.AUXService = new Service.ContactSensor(this.name); + this.AUXService.getCharacteristic(Characteristic.ContactSensorState) + .on('get', (callback) => { + this.log.debug(sprintf("getContactSensorState %s = %s",this.address, this.state)); + callback(null, this.state); + }); + break; + } + + return [service, this.AUXService]; + } +} + +class MHAlarm { + constructor(log, config) { + this.config = config || {}; + this.mh = config.parent.controller; + this.name = config.name; + this.displayName = config.name; + this.UUID = UUIDGen.generate(sprintf("alarm-%s",config.address)); + this.log = log; + + this.state = Characteristic.SecuritySystemCurrentState.DISARMED; + this.target = Characteristic.SecuritySystemCurrentState.DISARMED; + this.fault = Characteristic.StatusFault.NO_FAULT; + this.tampered = Characteristic.StatusTampered.NOT_TAMPERED; + this.lowbattery = Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL; + this.batterycharging = Characteristic.ChargingState.NOT_CHARGING; + this.batterylevel = 100; + this.zone = [true, true,true,true,false,false,false,false]; + this.active = false; + this.triggered = false; + + this.log.info(sprintf("LegrandMyHome::MHAlarm create object")); + + } + + getServices() { + var service = new Service.AccessoryInformation(); + service.setCharacteristic(Characteristic.Name, this.name) + .setCharacteristic(Characteristic.Manufacturer, "Legrand MyHome") + .setCharacteristic(Characteristic.Model, "Alarm 3486") + .setCharacteristic(Characteristic.SerialNumber, "Address " + this.address); + + this.alarmService = new Service.SecuritySystem(this.name); + this.alarmService.getCharacteristic(Characteristic.SecuritySystemCurrentState) + .on('get', (callback) => { + this.log.debug(sprintf("alarm current = %d",this.state)); + callback(null, this.state); + }); + this.alarmService.getCharacteristic(Characteristic.SecuritySystemTargetState) + .on('get', (callback) => { + this.log.debug(sprintf("alarm get target = %d",this.target)); + callback(null, this.target); + }) .on('set', (value,callback) => { - this.log.info(sprintf("setOn %s = %s",this.address, value)); + this.log.debug(sprintf("alarm set target= %d", this.target)); callback(null); }) + this.alarmService.getCharacteristic(Characteristic.StatusFault) .on('get', (callback) => { - this.log.info(sprintf("getOn %s",this.address)); - callback(null,0); + this.log.debug(sprintf("getConsumptio = %s",this.value)); + callback(null, this.fault); }); - return [service, this.statelessSwitch]; + this.alarmService.getCharacteristic(Characteristic.StatusTampered) + .on('get', (callback) => { + this.log.debug(sprintf("getConsumptio = %s",this.value)); + callback(null, this.tampered); + }); + this.alarmBatteryService = new Service.BatteryService(this.name); + this.alarmBatteryService.getCharacteristic(Characteristic.StatusLowBattery) + .on('get', (callback) => { + this.log.debug(sprintf("alarm current = %d",this.state)); + callback(null, this.lowbattery); + }); + this.alarmBatteryService.getCharacteristic(Characteristic.BatteryLevel) + .on('get', (callback) => { + this.log.debug(sprintf("alarm current = %d",this.state)); + callback(null, this.batterylevel); + }); + this.alarmBatteryService.getCharacteristic(Characteristic.ChargingState) + .on('get', (callback) => { + this.log.debug(sprintf("alarm current = %d",this.state)); + callback(null, this.batterycharging); + }); + + + return [service, this.alarmService, this.alarmBatteryService]; + } +} + +class MHControlledLoad { + constructor(log, config) { + this.config = config || {}; + this.mh = config.parent.controller; + this.name = config.name; + this.address = config.address; + this.displayName = config.name; + this.UUID = UUIDGen.generate(sprintf("controlledload-%s",config.address)); + this.log = log; + + this.enabled = true; + this.forced = 0; + this.log.info(sprintf("LegrandMyHome::MHControlledLoad create priority: %s", this.address)); + } + + getServices() { + var service = new Service.AccessoryInformation(); + service.setCharacteristic(Characteristic.Name, this.name) + .setCharacteristic(Characteristic.Manufacturer, "Legrand MyHome") + .setCharacteristic(Characteristic.Model, "Controlled load") + .setCharacteristic(Characteristic.SerialNumber, "Priority " + this.address); + + this.controlledLoad = new LegrandMyHome.ControlledLoadService(this.name); + + this.controlledLoad.getCharacteristic(Characteristic.Active) + .on('set', (value,callback) => { + this.log.debug(sprintf("setOn %s = %s",this.address, value)); + + if (value == 1) + { + this.enabled = true; + this.forced = value; + this.mh.forcedLoadCommand(this.address,this.forced); + callback(null); + } + else + { + this.forced = 0; + this.controlledLoad.getCharacteristic(Characteristic.Active).getValue(null); + setTimeout(function() { + this.forced = 1; + this.controlledLoad.getCharacteristic(Characteristic.Active).getValue(null); + }.bind(this),500); + callback(null); + } + + }) + .on('get', (callback) => { + this.log.debug(sprintf("getOn %s",this.address)); + callback(null,this.forced); + }); + this.controlledLoad.getCharacteristic(Characteristic.OutletInUse) + .on('get', (callback) => { + this.log.debug(sprintf("getOn %s",this.address)); + callback(null,this.enabled); + }); + return [service, this.controlledLoad]; } + } \ No newline at end of file diff --git a/lib/mhclient.js b/lib/mhclient.js old mode 100644 new mode 100755 index 7d88e28..aa53093 --- a/lib/mhclient.js +++ b/lib/mhclient.js @@ -3,7 +3,7 @@ const sprintf = require("sprintf-js").sprintf; const net = require('net'); const crypto = require('crypto'); const sha256 = require('sha256'), sha1 = require('sha1'); - +const moment = require('moment'); function inArray(needle, haystack) { @@ -21,20 +21,21 @@ function inArray(needle, haystack) { class MyHomeClient { - constructor(_ipaddress, _port, _password, _classToCallback) { + constructor(_ipaddress, _port, _password, _setclock, _classToCallback) { // Ten level translation, 0=0=Off, 1 = 100=On, 2=1%, 3=10%, 4=20%...8=60%,9=75,10=100% - this.dimmerLevels = [0,100,1,10,20,30,40,50,60,75,100]; + this.dimmerLevels = [0,100,20,30,40,50,60,70,80,90,100]; this.buffers = {}; this.lightBuses = []; this.ipaddress = _ipaddress; this.password = _password; this.port = _port; + this.setclock = _setclock; this.parent = _classToCallback; } start() { - this.monitor = new MyHomeConnection(this.ipaddress, this.port, this.password, "MONITOR", null, this.onMonitor.bind(this)); - this.command = new MyHomeConnection(this.ipaddress, this.port, this.password, "COMMAND", this.onCommandConnect.bind(this), this.onCommand.bind(this)); + this.monitor = new MyHomeConnection(this.ipaddress, this.port, this.password, "MONITOR", null, this.onMonitor.bind(this), null); + this.command = new MyHomeConnection(this.ipaddress, this.port, this.password, "COMMAND", this.onCommandConnect.bind(this), this.onCommand.bind(this), this.setclock); } /** @@ -58,12 +59,19 @@ class MyHomeClient { var b = parseInt(address[0]), a = parseInt(address[1]), pl = parseInt(address[2]); - if (b == 0) { + if (b == 0) + { if (a >= 10 || pl >= 10) { return sprintf("%02d%02d",a,pl); } - return sprintf("%d%d",a,pl); - } else { + else + if (pl==0) + return sprintf("%d",a); + else + return sprintf("%d%d",a,pl); + } + else + { if (a >= 10 || pl >= 10) { return sprintf("%02d%02d#4#%02d",a,pl,b); } @@ -74,6 +82,7 @@ class MyHomeClient { _addressToSlashes(_address) { if (_address.length == 4) return sprintf("0/%d/%d", parseInt(_address.substring(0,2)),parseInt(_address.substring(2,4))) if (_address.length == 2) return sprintf("0/%d/%d", parseInt(_address.substring(0,1)),parseInt(_address.substring(1,2))) + if (_address.length == 1) return sprintf("0/%d/0", parseInt(_address)) // TODO return "9/99/99"; } @@ -107,6 +116,8 @@ class MyHomeClient { this.command.send(sprintf("*2*%d*%s##",0,address)); } this.command.send(sprintf("*2*%d*%s##",parseInt(_stopUpDown),address)); + + } advancedBlindCommand(_address,_shutterLevel) { @@ -131,6 +142,14 @@ class MyHomeClient { this._bufferCommand("DIMMER",address,sprintf("*1*0*%s##",address),500); } } + + forcedLoadCommand(_address,_forced) + { + if (_address == "") return; + if (_forced == 1) + this.command.send(sprintf("*3*2*#%d##",_address)); + + } setSetPoint(_address,_temperature) { // Standard thermostat *4*40*%02d##*#4*#%02d*#14*%04d*3 @@ -151,6 +170,12 @@ class MyHomeClient { this.command.send(sprintf("*#1*0#4#%02d##",element)); } }, this); + + //request also AUX states + this.command.send("*#9##"); + + //request also controlled load states + this.command.send("*#3##"); /* Light status well keep some seconds, so I prefer to wait to send the connect feedback */ setTimeout(function() { @@ -175,9 +200,11 @@ class MyHomeClient { if (extract[1] <= 1) { if (this.parent != null && this.parent.onMonitor != null && typeof(this.parent.onRelay) == 'function') this.parent.onRelay(address,extract[1] == 1); debug(sprintf("LIGHTLEVEL %s ADDRESS %s",extract[1],address)); - } else { - if (this.parent != null && this.parent.onMonitor != null && typeof(this.parent.onDimmer) == 'function') this.parent.onDimmer(address,this.dimmerLevels[parseInt(extract[1],10)]); - } + } else + if (parseInt(extract[1],10) <= 10) + { + if (this.parent != null && this.parent.onMonitor != null && typeof(this.parent.onDimmer) == 'function') this.parent.onDimmer(address,this.dimmerLevels[parseInt(extract[1],10)]); + } } /* Light level - Advanced (VantageControls) way */ @@ -272,8 +299,110 @@ class MyHomeClient { if (extract) { var value = parseInt(extract[1],10) == 1 ? true : false; var address = parseInt(extract[2],10); - if (this.parent != null && this.parent.onMonitor != null && typeof(this.parent.onContactSensor) == 'function') this.parent.onContactSensor(address,value); + if (this.parent != null && this.parent.onMonitor != null && typeof(this.parent.onDryContact) == 'function') this.parent.onDryContact(address,value); debug(sprintf("DRYCONTACT %s ADDRESS %s",value,address)); + } + // AUX: *9*[0,9]*## OFF + // AUX: *9*1*## ON + extract = frame.match(/^\*9\*(\d)\*(\d)$/); + if (extract) { + var value = false; + if (parseInt(extract[1],10) == 0 || parseInt(extract[1],10)==9) + value = false; + else + value = true; + var address = parseInt(extract[2],10); + if (this.parent != null && this.parent.onMonitor != null && typeof(this.parent.onAUX) == 'function') + this.parent.onAUX(address,value); + debug(sprintf("AUX %s ADDRESS %s",value,address)); + } + + //powermeter + extract = frame.match(/^\*#3\*10\*3\*(\d+)$/); + if (extract) { + var value = parseInt(extract[1],10); + if (this.parent != null && this.parent.onMonitor != null && typeof(this.parent.onPowerMeter) == 'function') + this.parent.onPowerMeter(value); + debug(sprintf("Power %s W",value)); + } + + // + //controlled load + extract = frame.match(/^\*3\*(\d)\*#(\d)$/); + if (extract) { + var value = parseInt(extract[1],10); + var address = parseInt(extract[2],10); + if (this.parent != null && this.parent.onMonitor != null && typeof(this.parent.onControlledLoad) == 'function') + this.parent.onControlledLoad(address,value); + } + + //alarm status + extract = frame.match(/^\*5\*(\d+)\*0*$/); + if (extract) { + var value = parseInt(extract[1],10); + switch (value){ + case 0: + + break; + case 1: + + break; + case 8: //engaged + if (this.parent != null && this.parent.onMonitor != null && typeof(this.parent.onAlarm) == 'function') + this.parent.onAlarm(1); + break; + case 9: //disengaged + if (this.parent != null && this.parent.onMonitor != null && typeof(this.parent.onAlarm) == 'function') + this.parent.onAlarm(3); + if (this.parent != null && this.parent.onMonitor != null && typeof(this.parent.onAlarmTampered) == 'function') + this.parent.onAlarmTampered(0); + break; + case 4: + case 10: //battery KO + if (this.parent != null && this.parent.onMonitor != null && typeof(this.parent.onAlarmLowBattery) == 'function') + this.parent.onAlarmLowBattery(1); + break; + case 5: //battery OK + if (this.parent != null && this.parent.onMonitor != null && typeof(this.parent.onAlarmLowBattery) == 'function') + this.parent.onAlarmLowBattery(0); + break; + case 6: //no network + if (this.parent != null && this.parent.onMonitor != null && typeof(this.parent.onAlarmFault) == 'function') + this.parent.onAlarmFault(1); + break; + case 7: //network ok + if (this.parent != null && this.parent.onMonitor != null && typeof(this.parent.onAlarmFault) == 'function') + this.parent.onAlarmFault(0); + break; + default: + } + } + + + //alarm triggered and zone selection + extract = frame.match(/^\*5\*(\d+)\*#(\d)$/); + if (extract) { + var value = parseInt(extract[1],10); + switch (value){ + case 11: //zone active + if (this.parent != null && this.parent.onMonitor != null && typeof(this.parent.onZoneActive) == 'function') + this.parent.onZoneActive(parseInt(extract[2],10)-1, true); + break; + case 18: //zone deactive + if (this.parent != null && this.parent.onMonitor != null && typeof(this.parent.onZoneActive) == 'function') + this.parent.onZoneActive(parseInt(extract[2],10)-1, false); + break; + case 15: //silent alarm + case 17: //intrusion + if (this.parent != null && this.parent.onMonitor != null && typeof(this.parent.onAlarm) == 'function') + this.parent.onAlarm(4); + break; + case 16: //tampering + if (this.parent != null && this.parent.onMonitor != null && typeof(this.parent.onAlarmTampered) == 'function') + this.parent.onAlarmTampered(1); + break; + default: + } } }.bind(this)); } @@ -285,11 +414,28 @@ class MyHomeClient { getContactState(_address) { this.command.send(sprintf("*#25*3%d##",_address)); } + + getRelayState(_address) { + this.command.send(sprintf("*#1*%s##",this._slashesToAddress(_address))); + } - getAdvancedBlindSate(_address) { + getAdvancedBlindState(_address) { this.command.send(sprintf("*#2*%s*10##",this._slashesToAddress(_address))); } + getPower(){ + this.command.send("*#3*10*3##"); + } + + getAlarmState(){ + this.command.send("*#5*0##"); + + } + + getControlledLoadState() { + this.command.send("*#3##"); + } + onCommand(_frame) { /* Who cares? */ } @@ -300,7 +446,7 @@ class MyHomeClient { */ class MyHomeConnection { - constructor(_ipaddress, _port, _password, _type, _onconnectcallback, _onmessagecallback) { + constructor(_ipaddress, _port, _password, _type, _onconnectcallback, _onmessagecallback, _setclock) { this.ipaddress = _ipaddress; this.password = _password; this.type = _type; @@ -316,14 +462,18 @@ class MyHomeConnection { this.timerhandle = null; this.reconnecthandle = null; this.disconnecthandle = null; + this.setclock = _setclock; this.keepaliveSeconds = 25; /* Send keepalive command frame every 25 seconds */ this.idleSeconds = 55; /* Drop idle/lost connections after 55 seconds */ this.reconnectSeconds = 5; /* reconnect after 5 seconds */ + this.updateTimeSeconds = 3600; /* Keepalive frame on command connection every this.keepaliveSeconds seconds */ if (this.type == "COMMAND") { setInterval(function(){ this.sendKeepalive(); }.bind(this), this.keepaliveSeconds * 1000); + if (this.setclock) + setInterval(function(){ this.updateDate(); }.bind(this), this.updateTimeSeconds * 1000); } this.connect(); @@ -516,7 +666,19 @@ class MyHomeConnection { sendKeepalive() { debug('Keealive[%s]: send keepalive', this.type); - if (this.isConnected) this.connection.write("*#13**15##"); + if (this.isConnected) + { + this.connection.write("*#13**15##"); + } + } + + updateDate(){ + if (this.isConnected) + { + var setDateTimeFrame = moment().format("*#13**#22*HH*mm*ss*001*0d*DD*MM*YYYY##"); + this.connection.write(setDateTimeFrame); + + } } calcHMAC(_in) { From 5021d5139d95e16d73895dfc394553495bfac37e Mon Sep 17 00:00:00 2001 From: Simone Tisa Date: Thu, 10 Aug 2017 14:12:45 +0200 Subject: [PATCH 02/96] added Eve-like history to Energy --- fakegato-history.js | 249 ++++++++++++++++++++++++++++++++++++++++++++ index.js | 43 ++++---- 2 files changed, 272 insertions(+), 20 deletions(-) create mode 100644 fakegato-history.js diff --git a/fakegato-history.js b/fakegato-history.js new file mode 100644 index 0000000..b1187f2 --- /dev/null +++ b/fakegato-history.js @@ -0,0 +1,249 @@ +'use strict'; + +var homebridge; +var Characteristic; + +module.exports = function(pHomebridge) { + if (pHomebridge && !homebridge) { + homebridge = pHomebridge; + Characteristic = homebridge.hap.Characteristic; + } + + var hexToBase64 = function(val) { + return new Buffer((''+val).replace(/[^0-9A-F]/ig, ''), 'hex').toString('base64'); + }, base64ToHex = function(val) { + if(!val) return val; + return new Buffer(val, 'base64').toString('hex'); + }, swap16 = function (val) { + return ((val & 0xFF) << 8) + | ((val >>> 8) & 0xFF); + }, swap32 = function (val) { + return ((val & 0xFF) << 24) + | ((val & 0xFF00) << 8) + | ((val >>> 8) & 0xFF00) + | ((val >>> 24) & 0xFF); + }, hexToHPA = function(val) { + return parseInt(swap16(val), 10); + }, hPAtoHex = function(val) { + return swap16(Math.round(val)).toString(16); + }, numToHex = function(val, len) { + var s = Number(val>>>0).toString(16); + if(s.length % 2 != 0) { + s = '0' + s; + } + if(len) { + return ('0000000000000' + s).slice(-1 * len); + } + return s; +} + + class S2R1Characteristic extends Characteristic { + constructor() { + super('S2R1', 'E863F116-079E-48FF-8F27-9C2605A29F52'); + this.setProps({ + format: Characteristic.Formats.DATA, + perms: [ + Characteristic.Perms.READ, Characteristic.Perms.NOTIFY + ] + }); + } + } + + class S2R2Characteristic extends Characteristic { + constructor() { + super('S2R2', 'E863F117-079E-48FF-8F27-9C2605A29F52'); + this.setProps({ + format: Characteristic.Formats.DATA, + perms: [ + Characteristic.Perms.READ, Characteristic.Perms.NOTIFY + ] + }); + } + } + + class S2W1Characteristic extends Characteristic { + constructor() { + super('S2W1', 'E863F11C-079E-48FF-8F27-9C2605A29F52'); + this.setProps({ + format: Characteristic.Formats.DATA, + perms: [ + Characteristic.Perms.WRITE + ] + }); + } + } + + class S2W2Characteristic extends Characteristic { + constructor() { + super('S2W2', 'E863F121-079E-48FF-8F27-9C2605A29F52'); + this.setProps({ + format: Characteristic.Formats.DATA, + perms: [ + Characteristic.Perms.WRITE + ] + }); + } + } + + class FakeGatoHistoryService extends homebridge.hap.Service { + constructor(accessoryType) { + super("History", 'E863F007-079E-48FF-8F27-9C2605A29F52'); + switch (accessoryType) + { + case "weather": + this.accessoryType116 = "03"; + this.accessoryType117 = "07"; + break; + case "energy": + this.accessoryType116 = "07"; + this.accessoryType117 = "1f"; + break; + case "room": + this.accessoryType116 = "04"; + this.accessoryType117 = "0f"; + break; + } + + + this.accessoryType=accessoryType; + this.nextAvailableEntry = 1; + this.history = []; + this.maxHistory = 100; + this.currentEntry = 1; + this.transfer=false; + this.setTime=true; + this.refTime=0; + + this.addCharacteristic(S2R1Characteristic); + + this.addCharacteristic(S2R2Characteristic) + .on('get', (callback) => { + if ((this.currentEntry { this.totalenergy = 0; callback(null); }); - this.powerLoggingService = new LegrandMyHome.PowerLogging(this.name); + + this.powerLoggingService = new LegrandMyHome.FakeGatoHistoryService("energy"); + //this.powerLoggingService = new LegrandMyHome.PowerLogging(this.name); /*this.powerLoggingService.getCharacteristic(LegrandMyHome.E863F116) .on('get', (callback) => { callback(null, null); From 61c4096276c69a96fb01065467b659ed83acd2f1 Mon Sep 17 00:00:00 2001 From: Simone Tisa Date: Thu, 10 Aug 2017 14:55:39 +0200 Subject: [PATCH 03/96] cleanup --- index.js | 59 +------------------------------------------------------- 1 file changed, 1 insertion(+), 58 deletions(-) diff --git a/index.js b/index.js index fb2081a..b68cec3 100644 --- a/index.js +++ b/index.js @@ -4,7 +4,6 @@ var sprintf = require("sprintf-js").sprintf, inherits = require("util").inherits var events = require('events'), util = require('util'), fs = require('fs'); var Accessory, Characteristic, Service, UUIDGen; var moment = require('moment'); -var FakeGatoHistoryService = require('./fakegato-history'); module.exports = function (homebridge) { Service = homebridge.hap.Service; @@ -55,42 +54,6 @@ module.exports = function (homebridge) { LegrandMyHome.ResetTotal.UUID = 'E863F112-079E-48FF-8F27-9C2605A29F52'; inherits(LegrandMyHome.ResetTotal, Characteristic); - /*LegrandMyHome.E863F117 = function() { - Characteristic.call(this, 'ReadTrunk2', 'E863F117-079E-48FF-8F27-9C2605A29F52'); - this.setProps({ - format: Characteristic.Formats.DATA, - perms: [Characteristic.Perms.READ, Characteristic.Perms.WRITE] - }); - this.value = this.getDefaultValue(); - }; - LegrandMyHome.E863F117.UUID = 'E863F117-079E-48FF-8F27-9C2605A29F52'; - inherits(LegrandMyHome.E863F117, Characteristic); - - - LegrandMyHome.E863F11C = function() { - Characteristic.call(this, 'WriteTrunk1', 'E863F11C-079E-48FF-8F27-9C2605A29F52'); - this.setProps({ - format: Characteristic.Formats.DATA, - perms: [Characteristic.Perms.WRITE] - }); - this.value = null; - }; - LegrandMyHome.E863F11C.UUID = 'E863F11C-079E-48FF-8F27-9C2605A29F52'; - inherits(LegrandMyHome.E863F11C, Characteristic); - - LegrandMyHome.E863F121 = function() { - Characteristic.call(this, 'WriteTrunk2', 'E863F121-079E-48FF-8F27-9C2605A29F52'); - this.setProps({ - format: Characteristic.Formats.DATA, - perms: [Characteristic.Perms.WRITE] - }); - this.value = null; - }; - LegrandMyHome.E863F121.UUID = 'E863F121-079E-48FF-8F27-9C2605A29F52'; - inherits(LegrandMyHome.E863F121, Characteristic);*/ - - - LegrandMyHome.PowerMeterService = function(displayName, subtype) { Service.call(this, displayName, '00000001-0000-1777-8000-775D67EC4377', subtype); this.addCharacteristic(LegrandMyHome.CurrentPowerConsumption); @@ -1178,9 +1141,6 @@ class MHThermometer { } class MHPowerMeter { - - - constructor(log, config) { this.config = config || {}; this.mh = config.parent.controller; @@ -1229,24 +1189,7 @@ class MHPowerMeter { }); this.powerLoggingService = new LegrandMyHome.FakeGatoHistoryService("energy"); - //this.powerLoggingService = new LegrandMyHome.PowerLogging(this.name); - /*this.powerLoggingService.getCharacteristic(LegrandMyHome.E863F116) - .on('get', (callback) => { - callback(null, null); - }); - this.powerLoggingService.getCharacteristic(LegrandMyHome.E863F117) - .on('get', (callback) => { - callback(null, null); - }); - this.powerLoggingService.getCharacteristic(LegrandMyHome.E863F11C) - .on('get', (callback) => { - callback(null, null); - }); - this.powerLoggingService.getCharacteristic(LegrandMyHome.E863F121) - .on('get', (callback) => { - callback(null, null); - });*/ - + return [service, this.powerMeterService, this.powerLoggingService]; } } From 2264904ff1126c046c5cfee1293a9138ea9f8ff5 Mon Sep 17 00:00:00 2001 From: Simone Tisa Date: Thu, 10 Aug 2017 18:05:56 +0200 Subject: [PATCH 04/96] average power every 10min and fix of entry length --- fakegato-history.js | 4 ++-- index.js | 18 ++++++++++++++++-- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/fakegato-history.js b/fakegato-history.js index b1187f2..3882669 100644 --- a/fakegato-history.js +++ b/fakegato-history.js @@ -147,13 +147,13 @@ module.exports = function(pHomebridge) { + numToHex(swap16(this.history[this.currentEntry].pressure*10),4))); break; case "energy": - console.log("Data: "+ "10 " + numToHex(swap16(this.currentEntry),4) + " 0000 " + console.log("Data: "+ "14 " + numToHex(swap16(this.currentEntry),4) + " 0000 " + numToHex(swap32(this.history[this.currentEntry].time-this.refTime-978307200),8) + this.accessoryType117 + "0000 0000" + numToHex(swap16(this.history[this.currentEntry].power*10),4) + "0000 0000"); - callback(null,hexToBase64('10' + numToHex(swap16(this.currentEntry),4)+ ' 0000 ' + callback(null,hexToBase64('14' + numToHex(swap16(this.currentEntry),4)+ ' 0000 ' + numToHex(swap32(this.history[this.currentEntry].time-this.refTime-978307200),8) + this.accessoryType117 + "0000 0000" diff --git a/index.js b/index.js index b68cec3..965d41b 100644 --- a/index.js +++ b/index.js @@ -281,7 +281,17 @@ class LegrandMyHome { if (accessory.powerMeterService !== undefined) { accessory.value = _value; accessory.totalenergy = accessory.totalenergy + _value * accessory.refresh / 3600 / 1000; - accessory.powerLoggingService.addEntry({time: moment().unix(), power:accessory.value}); + accessory.intPower = accessory.intPower + _value; + if (accessory.acquiredSamples Date: Fri, 11 Aug 2017 09:18:58 +0200 Subject: [PATCH 05/96] added accessory type in logging of history --- fakegato-history.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/fakegato-history.js b/fakegato-history.js index 3882669..a0a520b 100644 --- a/fakegato-history.js +++ b/fakegato-history.js @@ -125,7 +125,7 @@ module.exports = function(pHomebridge) { this.history[this.currentEntry].pressure==0 && this.history[this.currentEntry].humidity==0) || (this.history[this.currentEntry].power==0xFFFF) || (this.setTime==true)) { - console.log("Data: "+ "15" + numToHex(swap16(this.currentEntry),4) + "0000 0000 0000 81" + numToHex(swap32(this.refTime),8) +"0000 0000 00 0000"); + console.log("Data "+ this.accessoryType + ": 15" + numToHex(swap16(this.currentEntry),4) + "0000 0000 0000 81" + numToHex(swap32(this.refTime),8) +"0000 0000 00 0000"); callback(null,hexToBase64('15' + numToHex(swap16(this.currentEntry),4) +' 0000 0000 0000 81' + numToHex(swap32(this.refTime),8) + '0000 0000 00 0000')); this.setTime=false; } @@ -133,7 +133,7 @@ module.exports = function(pHomebridge) { switch (this.accessoryType) { case "weather": - console.log("Data: "+ "10 " + numToHex(swap16(this.currentEntry),4) + " 0000 " + console.log("Data "+ this.accessoryType + ": 10 " + numToHex(swap16(this.currentEntry),4) + " 0000 " + numToHex(swap32(this.history[this.currentEntry].time-this.refTime-978307200),8) + this.accessoryType117 + numToHex(swap16(this.history[this.currentEntry].temp*100),4) @@ -147,7 +147,7 @@ module.exports = function(pHomebridge) { + numToHex(swap16(this.history[this.currentEntry].pressure*10),4))); break; case "energy": - console.log("Data: "+ "14 " + numToHex(swap16(this.currentEntry),4) + " 0000 " + console.log("Data "+ this.accessoryType + ": 14 " + numToHex(swap16(this.currentEntry),4) + " 0000 " + numToHex(swap32(this.history[this.currentEntry].time-this.refTime-978307200),8) + this.accessoryType117 + "0000 0000" @@ -215,21 +215,21 @@ module.exports = function(pHomebridge) { this.getCharacteristic(S2R1Characteristic) .setValue(hexToBase64(numToHex(swap32(entry.time-this.refTime-978307200),8) + '00000000' + numToHex(swap32(this.refTime),8) + '0401020202' + this.accessoryType116 +'020f03' + numToHex(swap16(this.nextAvailableEntry),4) +'ed0f00000000000000000101')); - console.log("Next available entry: "+ this.nextAvailableEntry.toString(16)); - console.log("116: " + numToHex(swap32(entry.time-this.refTime-978307200),8) + '00000000' + numToHex(swap32(this.refTime),8) + '0401020202' + this.accessoryType116 +'020f03' + numToHex(swap16(this.nextAvailableEntry),4) +'ed0f00000000000000000101'); + console.log("Next available entry " + this.accessoryType + ": " + this.nextAvailableEntry.toString(16)); + console.log("116 " + this.accessoryType + ": " + numToHex(swap32(entry.time-this.refTime-978307200),8) + '00000000' + numToHex(swap32(this.refTime),8) + '0401020202' + this.accessoryType116 +'020f03' + numToHex(swap16(this.nextAvailableEntry),4) +'ed0f00000000000000000101'); } setCurrentS2W1(val, callback) { callback(null,val); - console.log("Data request: "+ base64ToHex(val)); + console.log("Data request " + this.accessoryType + ": "+ base64ToHex(val)); var valHex = base64ToHex(val); var substring = valHex.substring(4,12); var valInt = parseInt(substring,16); var address = swap32(valInt); var hexAddress= address.toString('16'); - console.log("Address requested: "+ hexAddress); + console.log("Address requested " + this.accessoryType + ": "+ hexAddress); if (this.transfer==false) { this.transfer=true; From f9fdea1c5a5089937a2a27817db7d82724ceb6ab Mon Sep 17 00:00:00 2001 From: Simone Tisa Date: Fri, 11 Aug 2017 15:11:17 +0200 Subject: [PATCH 06/96] fix to make history more reliable with multiple iOS devices --- fakegato-history.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/fakegato-history.js b/fakegato-history.js index a0a520b..838baec 100644 --- a/fakegato-history.js +++ b/fakegato-history.js @@ -164,7 +164,10 @@ module.exports = function(pHomebridge) { this.currentEntry++; } else + { this.transfer=false; + callback(null,hexToBase64('00')); + } }); @@ -184,6 +187,7 @@ module.exports = function(pHomebridge) { this.currentEntry = address; else this.currentEntry = 1; + this.transfer=true; } //in order to be consistent with Eve, entry address start from 1 @@ -232,7 +236,7 @@ module.exports = function(pHomebridge) { console.log("Address requested " + this.accessoryType + ": "+ hexAddress); if (this.transfer==false) { - this.transfer=true; + //this.transfer=true; this.sendHistory(address); } } From 76ca76e15f822a937a32687fa32b2a0137c155e4 Mon Sep 17 00:00:00 2001 From: Simone Tisa Date: Fri, 8 Sep 2017 16:05:50 +0200 Subject: [PATCH 07/96] moved fakegato_history outside for reuse with other plugins --- fakegato-history.js | 253 -------------------------------------------- index.js | 4 +- 2 files changed, 2 insertions(+), 255 deletions(-) delete mode 100644 fakegato-history.js diff --git a/fakegato-history.js b/fakegato-history.js deleted file mode 100644 index 838baec..0000000 --- a/fakegato-history.js +++ /dev/null @@ -1,253 +0,0 @@ -'use strict'; - -var homebridge; -var Characteristic; - -module.exports = function(pHomebridge) { - if (pHomebridge && !homebridge) { - homebridge = pHomebridge; - Characteristic = homebridge.hap.Characteristic; - } - - var hexToBase64 = function(val) { - return new Buffer((''+val).replace(/[^0-9A-F]/ig, ''), 'hex').toString('base64'); - }, base64ToHex = function(val) { - if(!val) return val; - return new Buffer(val, 'base64').toString('hex'); - }, swap16 = function (val) { - return ((val & 0xFF) << 8) - | ((val >>> 8) & 0xFF); - }, swap32 = function (val) { - return ((val & 0xFF) << 24) - | ((val & 0xFF00) << 8) - | ((val >>> 8) & 0xFF00) - | ((val >>> 24) & 0xFF); - }, hexToHPA = function(val) { - return parseInt(swap16(val), 10); - }, hPAtoHex = function(val) { - return swap16(Math.round(val)).toString(16); - }, numToHex = function(val, len) { - var s = Number(val>>>0).toString(16); - if(s.length % 2 != 0) { - s = '0' + s; - } - if(len) { - return ('0000000000000' + s).slice(-1 * len); - } - return s; -} - - class S2R1Characteristic extends Characteristic { - constructor() { - super('S2R1', 'E863F116-079E-48FF-8F27-9C2605A29F52'); - this.setProps({ - format: Characteristic.Formats.DATA, - perms: [ - Characteristic.Perms.READ, Characteristic.Perms.NOTIFY - ] - }); - } - } - - class S2R2Characteristic extends Characteristic { - constructor() { - super('S2R2', 'E863F117-079E-48FF-8F27-9C2605A29F52'); - this.setProps({ - format: Characteristic.Formats.DATA, - perms: [ - Characteristic.Perms.READ, Characteristic.Perms.NOTIFY - ] - }); - } - } - - class S2W1Characteristic extends Characteristic { - constructor() { - super('S2W1', 'E863F11C-079E-48FF-8F27-9C2605A29F52'); - this.setProps({ - format: Characteristic.Formats.DATA, - perms: [ - Characteristic.Perms.WRITE - ] - }); - } - } - - class S2W2Characteristic extends Characteristic { - constructor() { - super('S2W2', 'E863F121-079E-48FF-8F27-9C2605A29F52'); - this.setProps({ - format: Characteristic.Formats.DATA, - perms: [ - Characteristic.Perms.WRITE - ] - }); - } - } - - class FakeGatoHistoryService extends homebridge.hap.Service { - constructor(accessoryType) { - super("History", 'E863F007-079E-48FF-8F27-9C2605A29F52'); - switch (accessoryType) - { - case "weather": - this.accessoryType116 = "03"; - this.accessoryType117 = "07"; - break; - case "energy": - this.accessoryType116 = "07"; - this.accessoryType117 = "1f"; - break; - case "room": - this.accessoryType116 = "04"; - this.accessoryType117 = "0f"; - break; - } - - - this.accessoryType=accessoryType; - this.nextAvailableEntry = 1; - this.history = []; - this.maxHistory = 100; - this.currentEntry = 1; - this.transfer=false; - this.setTime=true; - this.refTime=0; - - this.addCharacteristic(S2R1Characteristic); - - this.addCharacteristic(S2R2Characteristic) - .on('get', (callback) => { - if ((this.currentEntry Date: Mon, 9 Oct 2017 17:48:32 +0200 Subject: [PATCH 08/96] use of setCorrectingInternal to improve time accuracy of historical data, version bump --- index.js | 3 ++- package.json | 10 ++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/index.js b/index.js index af97a5a..10468c2 100644 --- a/index.js +++ b/index.js @@ -4,6 +4,7 @@ var sprintf = require("sprintf-js").sprintf, inherits = require("util").inherits var events = require('events'), util = require('util'), fs = require('fs'); var Accessory, Characteristic, Service, UUIDGen; var moment = require('moment'); +var correctingInterval = require('correcting-interval'); module.exports = function (homebridge) { Service = homebridge.hap.Service; @@ -1167,7 +1168,7 @@ class MHPowerMeter { this.value = 0; this.totalenergy = 0; this.log.info(sprintf("LegrandMyHome::MHPowerMeter create object")); - setInterval(function(){ + correctingInterval.setCorrectingInterval(function(){ this.mh.getPower(); }.bind(this), this.refresh * 1000); } diff --git a/package.json b/package.json index dce4a10..ced855a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-myhome-tng", - "version": "0.0.18", + "version": "0.0.19", "description": "Legrand MyHome plugin for homebridge: https://github.com/nfarina/homebridge", "license": "MIT", "keywords": [ @@ -11,11 +11,11 @@ "homebridge": ">=0.2.0" }, "author": { - "name": "Angelo Conforti" + "name": "Angelo Conforti and Simone Tisa" }, "repository": { "type": "git", - "url": "https://github.com/angeloxx/homebridge-myhome" + "url": "https://github.com/simont77/homebridge-myhome" }, "dependencies": { "colorsys": "^1.0.9", @@ -27,6 +27,8 @@ "sprint-js": "^0.1.0", "sprintf-js": "^1.0.3", "wait-until": "^0.0.2", - "inherits": "^2.0.0" + "inherits": "^2.0.0", + "moment": "^2.18.1", + "correcting-interval":"^2.0.0" } } From 632eb66b5240e1855744c447e2d5841ff4d7a9eb Mon Sep 17 00:00:00 2001 From: Simone Tisa Date: Tue, 10 Oct 2017 22:04:46 +0200 Subject: [PATCH 09/96] dependencies update --- index.js | 2 +- package.json | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/index.js b/index.js index 10468c2..6eee7b7 100644 --- a/index.js +++ b/index.js @@ -11,7 +11,7 @@ module.exports = function (homebridge) { Characteristic = homebridge.hap.Characteristic; Accessory = homebridge.platformAccessory; UUIDGen = homebridge.hap.uuid; - var FakeGatoHistoryService = require('../fakegato-history/fakegato-history')(homebridge); + var FakeGatoHistoryService = require('fakegato-history')(homebridge); /* Try to map Elgato's outlet custom vars */ LegrandMyHome.CurrentPowerConsumption = function() { diff --git a/package.json b/package.json index ced855a..cf55a87 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-myhome-tng", - "version": "0.0.19", + "version": "0.1.0", "description": "Legrand MyHome plugin for homebridge: https://github.com/nfarina/homebridge", "license": "MIT", "keywords": [ @@ -29,6 +29,7 @@ "wait-until": "^0.0.2", "inherits": "^2.0.0", "moment": "^2.18.1", - "correcting-interval":"^2.0.0" + "correcting-interval":"^2.0.0", + "fakegato-history":"simont77/fakegato-history#semver:^0.3.0" } } From fde9156ac55e068d323eb069c28eead11386ceb6 Mon Sep 17 00:00:00 2001 From: Simone Tisa Date: Tue, 10 Oct 2017 22:14:24 +0200 Subject: [PATCH 10/96] fix --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index cf55a87..faaedc0 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,6 @@ "inherits": "^2.0.0", "moment": "^2.18.1", "correcting-interval":"^2.0.0", - "fakegato-history":"simont77/fakegato-history#semver:^0.3.0" + "fakegato-history":"simont77/fakegato-history#semver:^v0.3.0" } } From 969f7df2458089cef8953f278ac9cb23e60bebbc Mon Sep 17 00:00:00 2001 From: Simone Tisa Date: Tue, 10 Oct 2017 22:16:33 +0200 Subject: [PATCH 11/96] fix --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index faaedc0..31e32bc 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,6 @@ "inherits": "^2.0.0", "moment": "^2.18.1", "correcting-interval":"^2.0.0", - "fakegato-history":"simont77/fakegato-history#semver:^v0.3.0" + "fakegato-history":"simont77/fakegato-history#v0.3.0" } } From f0aa1145e098bbc72922062b8beaafdb56e90703 Mon Sep 17 00:00:00 2001 From: Simone Tisa Date: Tue, 10 Oct 2017 22:59:54 +0200 Subject: [PATCH 12/96] fix --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 31e32bc..cd13284 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,6 @@ "inherits": "^2.0.0", "moment": "^2.18.1", "correcting-interval":"^2.0.0", - "fakegato-history":"simont77/fakegato-history#v0.3.0" + "fakegato-history":"simont77/fakegato-history#v0.3.1" } } From edfd3a158890cd38529eb4c8dbdadf0c4ad58b48 Mon Sep 17 00:00:00 2001 From: simont77 Date: Fri, 13 Oct 2017 17:53:50 +0200 Subject: [PATCH 13/96] moved accumulation of power into setCorrectingInterval call to improve accuracy --- index.js | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/index.js b/index.js index 6eee7b7..ada239e 100644 --- a/index.js +++ b/index.js @@ -281,7 +281,7 @@ class LegrandMyHome { this.devices.forEach(function(accessory) { if (accessory.powerMeterService !== undefined) { accessory.value = _value; - accessory.totalenergy = accessory.totalenergy + _value * accessory.refresh / 3600 / 1000; + /*accessory.totalenergy = accessory.totalenergy + _value * accessory.refresh / 3600 / 1000; accessory.intPower = accessory.intPower + _value; if (accessory.acquiredSamples Date: Sun, 22 Oct 2017 19:39:10 +0200 Subject: [PATCH 14/96] fix dimmer levels, version bump --- lib/mhclient.js | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/mhclient.js b/lib/mhclient.js index aa53093..a370004 100755 --- a/lib/mhclient.js +++ b/lib/mhclient.js @@ -23,7 +23,7 @@ class MyHomeClient { constructor(_ipaddress, _port, _password, _setclock, _classToCallback) { // Ten level translation, 0=0=Off, 1 = 100=On, 2=1%, 3=10%, 4=20%...8=60%,9=75,10=100% - this.dimmerLevels = [0,100,20,30,40,50,60,70,80,90,100]; + this.dimmerLevels = [0,100,1,10,20,30,40,50,60,75,100]; this.buffers = {}; this.lightBuses = []; this.ipaddress = _ipaddress; diff --git a/package.json b/package.json index cd13284..335ec17 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-myhome-tng", - "version": "0.1.0", + "version": "0.1.1", "description": "Legrand MyHome plugin for homebridge: https://github.com/nfarina/homebridge", "license": "MIT", "keywords": [ From 9b84ee5e272b75863b3fdfdbbd57ca9777ba1977 Mon Sep 17 00:00:00 2001 From: simont77 Date: Wed, 20 Dec 2017 10:52:43 +0100 Subject: [PATCH 15/96] Update package.json --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 335ec17..f5cb0ab 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-myhome-tng", - "version": "0.1.1", + "version": "0.1.2", "description": "Legrand MyHome plugin for homebridge: https://github.com/nfarina/homebridge", "license": "MIT", "keywords": [ @@ -30,6 +30,6 @@ "inherits": "^2.0.0", "moment": "^2.18.1", "correcting-interval":"^2.0.0", - "fakegato-history":"simont77/fakegato-history#v0.3.1" + "fakegato-history":"^0.3.2" } } From 0d112090f430ea12b311294d96c146667d31a0f5 Mon Sep 17 00:00:00 2001 From: Simone Tisa Date: Sun, 7 Jan 2018 16:40:58 +0100 Subject: [PATCH 16/96] history added for motion and door --- index.js | 120 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 117 insertions(+), 3 deletions(-) diff --git a/index.js b/index.js index ada239e..ac0b847 100644 --- a/index.js +++ b/index.js @@ -13,7 +13,7 @@ module.exports = function (homebridge) { UUIDGen = homebridge.hap.uuid; var FakeGatoHistoryService = require('fakegato-history')(homebridge); - /* Try to map Elgato's outlet custom vars */ + /* Try to map Elgato custom vars */ LegrandMyHome.CurrentPowerConsumption = function() { Characteristic.call(this, 'Consumption', 'E863F10D-079E-48FF-8F27-9C2605A29F52'); this.setProps({ @@ -55,6 +55,78 @@ module.exports = function (homebridge) { LegrandMyHome.ResetTotal.UUID = 'E863F112-079E-48FF-8F27-9C2605A29F52'; inherits(LegrandMyHome.ResetTotal, Characteristic); + LegrandMyHome.Sensitivity = function() { + Characteristic.call(this, 'Sensitivity', 'E863F120-079E-48FF-8F27-9C2605A29F52'); + this.setProps({ + format: Characteristic.Formats.UINT16, + maxValue: 7, + minValue: 0, + minStep: 1, + perms: [Characteristic.Perms.READ, Characteristic.Perms.WRITE] + }); + this.value = this.getDefaultValue(); + }; + LegrandMyHome.Sensitivity.UUID = 'E863F120-079E-48FF-8F27-9C2605A29F52'; + inherits(LegrandMyHome.Sensitivity, Characteristic); + + LegrandMyHome.Duration = function() { + Characteristic.call(this, 'Duration', 'E863F12D-079E-48FF-8F27-9C2605A29F52'); + this.setProps({ + format: Characteristic.Formats.UINT16, + maxValue: 3600, + minValue: 0, + minStep: 1, + perms: [Characteristic.Perms.READ, Characteristic.Perms.WRITE] + }); + this.value = this.getDefaultValue(); + }; + LegrandMyHome.Duration.UUID = 'E863F12D-079E-48FF-8F27-9C2605A29F52'; + inherits(LegrandMyHome.Duration, Characteristic); + + LegrandMyHome.LastActivation = function() { + Characteristic.call(this, 'LastActivation', 'E863F11A-079E-48FF-8F27-9C2605A29F52'); + this.setProps({ + format: Characteristic.Formats.UINT32, + perms: [Characteristic.Perms.READ, Characteristic.Perms.WRITE, Characteristic.Perms.NOTIFY] + }); + this.value = this.getDefaultValue(); + }; + LegrandMyHome.LastActivation.UUID = 'E863F11A-079E-48FF-8F27-9C2605A29F52'; + inherits(LegrandMyHome.LastActivation, Characteristic); + + LegrandMyHome.TimesOpened = function() { + Characteristic.call(this, 'TimesOpened', 'E863F129-079E-48FF-8F27-9C2605A29F52'); + this.setProps({ + format: Characteristic.Formats.UINT32, + perms: [Characteristic.Perms.READ, Characteristic.Perms.WRITE, Characteristic.Perms.NOTIFY] + }); + this.value = this.getDefaultValue(); + }; + LegrandMyHome.TimesOpened.UUID = 'E863F129-079E-48FF-8F27-9C2605A29F52'; + inherits(LegrandMyHome.TimesOpened, Characteristic); + + LegrandMyHome.Char118 = function() { + Characteristic.call(this, 'Char118', 'E863F118-079E-48FF-8F27-9C2605A29F52'); + this.setProps({ + format: Characteristic.Formats.UINT32, + perms: [Characteristic.Perms.READ, Characteristic.Perms.WRITE, Characteristic.Perms.NOTIFY] + }); + this.value = this.getDefaultValue(); + }; + LegrandMyHome.Char118.UUID = 'E863F118-079E-48FF-8F27-9C2605A29F52'; + inherits(LegrandMyHome.Char118, Characteristic); + + LegrandMyHome.Char119 = function() { + Characteristic.call(this, 'Char119', 'E863F119-079E-48FF-8F27-9C2605A29F52'); + this.setProps({ + format: Characteristic.Formats.UINT32, + perms: [Characteristic.Perms.READ, Characteristic.Perms.WRITE, Characteristic.Perms.NOTIFY] + }); + this.value = this.getDefaultValue(); + }; + LegrandMyHome.Char119.UUID = 'E863F119-079E-48FF-8F27-9C2605A29F52'; + inherits(LegrandMyHome.Char119, Characteristic); + LegrandMyHome.PowerMeterService = function(displayName, subtype) { Service.call(this, displayName, '00000001-0000-1777-8000-775D67EC4377', subtype); this.addCharacteristic(LegrandMyHome.CurrentPowerConsumption); @@ -1271,11 +1343,17 @@ class MHDryContact { this.UUID = UUIDGen.generate(sprintf("drycontact-%s",config.address)); this.log = log; this.type = config.type; - + this.numberOpened = 0; + this.state = config.state || false; this.log.info(sprintf("LegrandMyHome::MHDryContact create object: %s", this.address)); } + identify(callback) { + this.log("Identify requested!"); + callback(); // success + } + getServices() { var service = new Service.AccessoryInformation(); service.setCharacteristic(Characteristic.Name, this.name) @@ -1286,11 +1364,35 @@ class MHDryContact { switch (this.type) { case 'Contact': this.dryContactService = new Service.ContactSensor(this.name); + this.LoggingService = new LegrandMyHome.FakeGatoHistoryService("door", this); + this.dryContactService.addCharacteristic(LegrandMyHome.LastActivation); + this.dryContactService.addCharacteristic(LegrandMyHome.TimesOpened); + this.dryContactService.addCharacteristic(LegrandMyHome.ResetTotal); + this.dryContactService.addCharacteristic(LegrandMyHome.Char118); + this.dryContactService.addCharacteristic(LegrandMyHome.Char119); this.dryContactService.getCharacteristic(Characteristic.ContactSensorState) .on('get', (callback) => { this.log.debug(sprintf("getContactSensorState %s = %s",this.address, this.state)); callback(null, this.state); }); + this.dryContactService.getCharacteristic(Characteristic.ContactSensorState) + .on('change', () => { + this.log.debug(sprintf("changeContactSensorState %s = %s",this.address, this.state)); + this.LoggingService.addEntry({time: moment().unix(), status: this.state}); + if (this.state) + this.numberOpened++; + }); + this.dryContactService.getCharacteristic(LegrandMyHome.ResetTotal) + .on('set', (value, callback) => { + this.numberOpened = 0; + callback(null); + }); + this.dryContactService.getCharacteristic(LegrandMyHome.TimesOpened) + .on('get', (callback) => { + this.log.debug(sprintf("getNumberOpened = %f",this.numberOpened)); + callback(null, this.numberOpened); + }); + return [service, this.dryContactService, this.LoggingService]; break; case 'Leak': this.dryContactService = new Service.LeakSensor(this.name); @@ -1299,14 +1401,25 @@ class MHDryContact { this.log.debug(sprintf("getLeakSensorState %s = %s",this.address, this.state)); callback(null, this.state); }); + return [service, this.dryContactService]; break; case 'Motion': this.dryContactService = new Service.MotionSensor(this.name); + this.LoggingService = new LegrandMyHome.FakeGatoHistoryService("motion", this); + this.dryContactService.addCharacteristic(LegrandMyHome.Sensitivity); + this.dryContactService.addCharacteristic(LegrandMyHome.Duration); + this.dryContactService.addCharacteristic(LegrandMyHome.LastActivation); this.dryContactService.getCharacteristic(Characteristic.MotionDetected) .on('get', (callback) => { this.log.debug(sprintf("getMotionSensorState %s = %s",this.address, this.state)); callback(null, this.state); }); + this.dryContactService.getCharacteristic(Characteristic.MotionDetected) + .on('change', () => { + this.log.debug(sprintf("changeMotionSensorState %s = %s",this.address, this.state)); + this.LoggingService.addEntry({time: moment().unix(), status: this.state}); + }); + return [service, this.dryContactService, this.LoggingService]; break; default: this.dryContactService = new Service.ContactSensor(this.name); @@ -1315,10 +1428,11 @@ class MHDryContact { this.log.debug(sprintf("getContactSensorState %s = %s",this.address, this.state)); callback(null, this.state); }); + return [service, this.dryContactService]; break; } - return [service, this.dryContactService]; + } } From e5d0aa7338e3b314d0362ede8e367bd9c1db12db Mon Sep 17 00:00:00 2001 From: simont77 Date: Mon, 8 Jan 2018 18:03:35 +0100 Subject: [PATCH 17/96] added programmable duration to motion --- index.js | 38 ++++++++++++++++++++++++++++++++------ 1 file changed, 32 insertions(+), 6 deletions(-) diff --git a/index.js b/index.js index ac0b847..1f424e6 100644 --- a/index.js +++ b/index.js @@ -279,15 +279,29 @@ class LegrandMyHome { onDryContact(_address,_state) { this.devices.forEach(function(accessory) { if (accessory.address == _address && accessory.dryContactService !== undefined) { - accessory.state = _state; + switch (accessory.type) { - case 'Contact': accessory.dryContactService.getCharacteristic(Characteristic.ContactSensorState).getValue(null); + case 'Contact': + accessory.state = _state; + accessory.dryContactService.getCharacteristic(Characteristic.ContactSensorState).getValue(null); break; - case 'Leak': accessory.dryContactService.getCharacteristic(Characteristic.LeakDetected).getValue(null); + case 'Leak': + accessory.state = _state; accessory.dryContactService.getCharacteristic(Characteristic.LeakDetected).getValue(null); break; - case 'Motion': accessory.dryContactService.getCharacteristic(Characteristic.MotionDetected).getValue(null); + case 'Motion': + if (_state==true) + { + accessory.state = true; + accessory.dryContactService.getCharacteristic(Characteristic.MotionDetected).getValue(null); + clearTimeout(accessory.durationhandle); + accessory.durationhandle = setTimeout(function() { + accessory.state = false; + accessory.dryContactService.getCharacteristic(Characteristic.MotionDetected).getValue(null); + }.bind(this), accessory.duration * 1000); + } break; - default: accessory.dryContactService.getCharacteristic(Characteristic.ContactSensorState).getValue(null); + default: + accessory.state = _state; accessory.dryContactService.getCharacteristic(Characteristic.ContactSensorState).getValue(null); break; } } @@ -1344,6 +1358,8 @@ class MHDryContact { this.log = log; this.type = config.type; this.numberOpened = 0; + this.durationhandle = null; + this.duration = 30; this.state = config.state || false; this.log.info(sprintf("LegrandMyHome::MHDryContact create object: %s", this.address)); @@ -1408,7 +1424,8 @@ class MHDryContact { this.LoggingService = new LegrandMyHome.FakeGatoHistoryService("motion", this); this.dryContactService.addCharacteristic(LegrandMyHome.Sensitivity); this.dryContactService.addCharacteristic(LegrandMyHome.Duration); - this.dryContactService.addCharacteristic(LegrandMyHome.LastActivation); + this.dryContactService.addCharacteristic(LegrandMyHome.LastActivation); + this.dryContactService.setCharacteristic(LegrandMyHome.Duration,this.duration); this.dryContactService.getCharacteristic(Characteristic.MotionDetected) .on('get', (callback) => { this.log.debug(sprintf("getMotionSensorState %s = %s",this.address, this.state)); @@ -1419,6 +1436,15 @@ class MHDryContact { this.log.debug(sprintf("changeMotionSensorState %s = %s",this.address, this.state)); this.LoggingService.addEntry({time: moment().unix(), status: this.state}); }); + this.dryContactService.getCharacteristic(LegrandMyHome.Duration) + .on('set', (value, callback) => { + this.duration = value; + callback(null); + }) + .on('get', (callback) => { + callback(null, this.duration); + }); + return [service, this.dryContactService, this.LoggingService]; break; default: From 0dff48f1abb1cabd52392db4322599e3cf2872b4 Mon Sep 17 00:00:00 2001 From: simont77 Date: Tue, 9 Jan 2018 16:35:05 +0100 Subject: [PATCH 18/96] cleanup --- index.js | 123 +++++++++++++++++++++++++++---------------------------- 1 file changed, 61 insertions(+), 62 deletions(-) diff --git a/index.js b/index.js index 1f424e6..d1bfa24 100644 --- a/index.js +++ b/index.js @@ -5,6 +5,7 @@ var events = require('events'), util = require('util'), fs = require('fs'); var Accessory, Characteristic, Service, UUIDGen; var moment = require('moment'); var correctingInterval = require('correcting-interval'); +const version = require('./package.json').version; module.exports = function (homebridge) { Service = homebridge.hap.Service; @@ -14,7 +15,7 @@ module.exports = function (homebridge) { var FakeGatoHistoryService = require('fakegato-history')(homebridge); /* Try to map Elgato custom vars */ - LegrandMyHome.CurrentPowerConsumption = function() { + Elgato.CurrentPowerConsumption = function() { Characteristic.call(this, 'Consumption', 'E863F10D-079E-48FF-8F27-9C2605A29F52'); this.setProps({ format: Characteristic.Formats.UINT16, @@ -26,10 +27,10 @@ module.exports = function (homebridge) { }); this.value = this.getDefaultValue(); }; - LegrandMyHome.CurrentPowerConsumption.UUID = 'E863F10D-079E-48FF-8F27-9C2605A29F52'; - inherits(LegrandMyHome.CurrentPowerConsumption, Characteristic); + Elgato.CurrentPowerConsumption.UUID = 'E863F10D-079E-48FF-8F27-9C2605A29F52'; + inherits(Elgato.CurrentPowerConsumption, Characteristic); - LegrandMyHome.TotalConsumption = function() { + Elgato.TotalConsumption = function() { Characteristic.call(this, 'Energy', 'E863F10C-079E-48FF-8F27-9C2605A29F52'); this.setProps({ format: Characteristic.Formats.FLOAT, @@ -41,10 +42,10 @@ module.exports = function (homebridge) { }); this.value = this.getDefaultValue(); }; - LegrandMyHome.TotalConsumption.UUID = 'E863F10C-079E-48FF-8F27-9C2605A29F52'; - inherits(LegrandMyHome.TotalConsumption, Characteristic); + Elgato.TotalConsumption.UUID = 'E863F10C-079E-48FF-8F27-9C2605A29F52'; + inherits(Elgato.TotalConsumption, Characteristic); - LegrandMyHome.ResetTotal = function() { + Elgato.ResetTotal = function() { Characteristic.call(this, 'Reset', 'E863F112-079E-48FF-8F27-9C2605A29F52'); this.setProps({ format: Characteristic.Formats.UINT32, @@ -52,10 +53,10 @@ module.exports = function (homebridge) { }); this.value = this.getDefaultValue(); }; - LegrandMyHome.ResetTotal.UUID = 'E863F112-079E-48FF-8F27-9C2605A29F52'; - inherits(LegrandMyHome.ResetTotal, Characteristic); + Elgato.ResetTotal.UUID = 'E863F112-079E-48FF-8F27-9C2605A29F52'; + inherits(Elgato.ResetTotal, Characteristic); - LegrandMyHome.Sensitivity = function() { + Elgato.Sensitivity = function() { Characteristic.call(this, 'Sensitivity', 'E863F120-079E-48FF-8F27-9C2605A29F52'); this.setProps({ format: Characteristic.Formats.UINT16, @@ -66,10 +67,10 @@ module.exports = function (homebridge) { }); this.value = this.getDefaultValue(); }; - LegrandMyHome.Sensitivity.UUID = 'E863F120-079E-48FF-8F27-9C2605A29F52'; - inherits(LegrandMyHome.Sensitivity, Characteristic); + Elgato.Sensitivity.UUID = 'E863F120-079E-48FF-8F27-9C2605A29F52'; + inherits(Elgato.Sensitivity, Characteristic); - LegrandMyHome.Duration = function() { + Elgato.Duration = function() { Characteristic.call(this, 'Duration', 'E863F12D-079E-48FF-8F27-9C2605A29F52'); this.setProps({ format: Characteristic.Formats.UINT16, @@ -80,10 +81,10 @@ module.exports = function (homebridge) { }); this.value = this.getDefaultValue(); }; - LegrandMyHome.Duration.UUID = 'E863F12D-079E-48FF-8F27-9C2605A29F52'; - inherits(LegrandMyHome.Duration, Characteristic); + Elgato.Duration.UUID = 'E863F12D-079E-48FF-8F27-9C2605A29F52'; + inherits(Elgato.Duration, Characteristic); - LegrandMyHome.LastActivation = function() { + Elgato.LastActivation = function() { Characteristic.call(this, 'LastActivation', 'E863F11A-079E-48FF-8F27-9C2605A29F52'); this.setProps({ format: Characteristic.Formats.UINT32, @@ -91,10 +92,10 @@ module.exports = function (homebridge) { }); this.value = this.getDefaultValue(); }; - LegrandMyHome.LastActivation.UUID = 'E863F11A-079E-48FF-8F27-9C2605A29F52'; - inherits(LegrandMyHome.LastActivation, Characteristic); + Elgato.LastActivation.UUID = 'E863F11A-079E-48FF-8F27-9C2605A29F52'; + inherits(Elgato.LastActivation, Characteristic); - LegrandMyHome.TimesOpened = function() { + Elgato.TimesOpened = function() { Characteristic.call(this, 'TimesOpened', 'E863F129-079E-48FF-8F27-9C2605A29F52'); this.setProps({ format: Characteristic.Formats.UINT32, @@ -102,10 +103,10 @@ module.exports = function (homebridge) { }); this.value = this.getDefaultValue(); }; - LegrandMyHome.TimesOpened.UUID = 'E863F129-079E-48FF-8F27-9C2605A29F52'; - inherits(LegrandMyHome.TimesOpened, Characteristic); + Elgato.TimesOpened.UUID = 'E863F129-079E-48FF-8F27-9C2605A29F52'; + inherits(Elgato.TimesOpened, Characteristic); - LegrandMyHome.Char118 = function() { + Elgato.Char118 = function() { Characteristic.call(this, 'Char118', 'E863F118-079E-48FF-8F27-9C2605A29F52'); this.setProps({ format: Characteristic.Formats.UINT32, @@ -113,10 +114,10 @@ module.exports = function (homebridge) { }); this.value = this.getDefaultValue(); }; - LegrandMyHome.Char118.UUID = 'E863F118-079E-48FF-8F27-9C2605A29F52'; - inherits(LegrandMyHome.Char118, Characteristic); + Elgato.Char118.UUID = 'E863F118-079E-48FF-8F27-9C2605A29F52'; + inherits(Elgato.Char118, Characteristic); - LegrandMyHome.Char119 = function() { + Elgato.Char119 = function() { Characteristic.call(this, 'Char119', 'E863F119-079E-48FF-8F27-9C2605A29F52'); this.setProps({ format: Characteristic.Formats.UINT32, @@ -124,40 +125,38 @@ module.exports = function (homebridge) { }); this.value = this.getDefaultValue(); }; - LegrandMyHome.Char119.UUID = 'E863F119-079E-48FF-8F27-9C2605A29F52'; - inherits(LegrandMyHome.Char119, Characteristic); + Elgato.Char119.UUID = 'E863F119-079E-48FF-8F27-9C2605A29F52'; + inherits(Elgato.Char119, Characteristic); - LegrandMyHome.PowerMeterService = function(displayName, subtype) { + Elgato.PowerMeterService = function(displayName, subtype) { Service.call(this, displayName, '00000001-0000-1777-8000-775D67EC4377', subtype); - this.addCharacteristic(LegrandMyHome.CurrentPowerConsumption); - this.addCharacteristic(LegrandMyHome.TotalConsumption); - this.addCharacteristic(LegrandMyHome.ResetTotal); + this.addCharacteristic(Elgato.CurrentPowerConsumption); + this.addCharacteristic(Elgato.TotalConsumption); + this.addCharacteristic(Elgato.ResetTotal); }; - inherits(LegrandMyHome.PowerMeterService, Service); + inherits(Elgato.PowerMeterService, Service); - LegrandMyHome.FakeGatoHistoryService=FakeGatoHistoryService; - inherits(LegrandMyHome.FakeGatoHistoryService, Service); + Elgato.FakeGatoHistoryService=FakeGatoHistoryService; + inherits(Elgato.FakeGatoHistoryService, Service); - LegrandMyHome.ControlledLoadService = function(displayName, subtype) { + Elgato.ControlledLoadService = function(displayName, subtype) { Service.call(this, displayName, 'D43133F2-9BDE-4731-9FF2-B427189DCB4A', subtype); this.addCharacteristic(Characteristic.OutletInUse); this.addCharacteristic(Characteristic.Active); }; - inherits(LegrandMyHome.ControlledLoadService, Service); + inherits(Elgato.ControlledLoadService, Service); - LegrandMyHome.RainSensorService = function(displayName, subtype) { + Elgato.RainSensorService = function(displayName, subtype) { Service.call(this, displayName, '9018CDC8-DEF9-49D5-A969-63F8CCAAB1A6', subtype); this.addCharacteristic(Characteristic.CurrentRelativeHumidity); }; - inherits(LegrandMyHome.RainSensorService, Service); + inherits(Elgato.RainSensorService, Service); process.setMaxListeners(0); homebridge.registerPlatform("homebridge-myhome", "LegrandMyHome", LegrandMyHome); }; - - class LegrandMyHome { constructor(log, config, api) { this.log = log; @@ -1267,8 +1266,8 @@ class MHPowerMeter { this.acquiredSamples=0; this.intPower=0; } - this.powerMeterService.getCharacteristic(LegrandMyHome.CurrentPowerConsumption).getValue(null); - this.powerMeterService.getCharacteristic(LegrandMyHome.TotalConsumption).getValue(null); + this.powerMeterService.getCharacteristic(Elgato.CurrentPowerConsumption).getValue(null); + this.powerMeterService.getCharacteristic(Elgato.TotalConsumption).getValue(null); this.mh.getPower(); }.bind(this), this.refresh * 1000); @@ -1287,24 +1286,24 @@ class MHPowerMeter { .setCharacteristic(Characteristic.Model, "Power Meter") .setCharacteristic(Characteristic.SerialNumber, "Address " + this.address); - this.powerMeterService = new LegrandMyHome.PowerMeterService(this.name); - this.powerMeterService.getCharacteristic(LegrandMyHome.CurrentPowerConsumption) + this.powerMeterService = new Elgato.PowerMeterService(this.name); + this.powerMeterService.getCharacteristic(Elgato.CurrentPowerConsumption) .on('get', (callback) => { this.log.debug(sprintf("getConsumptio = %s",this.value)); callback(null, this.value); }); - this.powerMeterService.getCharacteristic(LegrandMyHome.TotalConsumption) + this.powerMeterService.getCharacteristic(Elgato.TotalConsumption) .on('get', (callback) => { this.log.debug(sprintf("getConsumptio = %f",this.totalenergy)); callback(null, this.totalenergy); }); - this.powerMeterService.getCharacteristic(LegrandMyHome.ResetTotal) + this.powerMeterService.getCharacteristic(Elgato.ResetTotal) .on('set', (value, callback) => { this.totalenergy = 0; callback(null); }); - this.powerLoggingService = new LegrandMyHome.FakeGatoHistoryService("energy", this); + this.powerLoggingService = new Elgato.FakeGatoHistoryService("energy", this); return [service, this.powerMeterService, this.powerLoggingService]; } @@ -1380,12 +1379,12 @@ class MHDryContact { switch (this.type) { case 'Contact': this.dryContactService = new Service.ContactSensor(this.name); - this.LoggingService = new LegrandMyHome.FakeGatoHistoryService("door", this); - this.dryContactService.addCharacteristic(LegrandMyHome.LastActivation); - this.dryContactService.addCharacteristic(LegrandMyHome.TimesOpened); - this.dryContactService.addCharacteristic(LegrandMyHome.ResetTotal); - this.dryContactService.addCharacteristic(LegrandMyHome.Char118); - this.dryContactService.addCharacteristic(LegrandMyHome.Char119); + this.LoggingService = new Elgato.FakeGatoHistoryService("door", this); + this.dryContactService.addCharacteristic(Elgato.LastActivation); + this.dryContactService.addCharacteristic(Elgato.TimesOpened); + this.dryContactService.addCharacteristic(Elgato.ResetTotal); + this.dryContactService.addCharacteristic(Elgato.Char118); + this.dryContactService.addCharacteristic(Elgato.Char119); this.dryContactService.getCharacteristic(Characteristic.ContactSensorState) .on('get', (callback) => { this.log.debug(sprintf("getContactSensorState %s = %s",this.address, this.state)); @@ -1398,12 +1397,12 @@ class MHDryContact { if (this.state) this.numberOpened++; }); - this.dryContactService.getCharacteristic(LegrandMyHome.ResetTotal) + this.dryContactService.getCharacteristic(Elgato.ResetTotal) .on('set', (value, callback) => { this.numberOpened = 0; callback(null); }); - this.dryContactService.getCharacteristic(LegrandMyHome.TimesOpened) + this.dryContactService.getCharacteristic(Elgato.TimesOpened) .on('get', (callback) => { this.log.debug(sprintf("getNumberOpened = %f",this.numberOpened)); callback(null, this.numberOpened); @@ -1421,11 +1420,11 @@ class MHDryContact { break; case 'Motion': this.dryContactService = new Service.MotionSensor(this.name); - this.LoggingService = new LegrandMyHome.FakeGatoHistoryService("motion", this); - this.dryContactService.addCharacteristic(LegrandMyHome.Sensitivity); - this.dryContactService.addCharacteristic(LegrandMyHome.Duration); - this.dryContactService.addCharacteristic(LegrandMyHome.LastActivation); - this.dryContactService.setCharacteristic(LegrandMyHome.Duration,this.duration); + this.LoggingService = new Elgato.FakeGatoHistoryService("motion", this); + this.dryContactService.addCharacteristic(Elgato.Sensitivity); + this.dryContactService.addCharacteristic(Elgato.Duration); + this.dryContactService.addCharacteristic(Elgato.LastActivation); + this.dryContactService.setCharacteristic(Elgato.Duration,this.duration); this.dryContactService.getCharacteristic(Characteristic.MotionDetected) .on('get', (callback) => { this.log.debug(sprintf("getMotionSensorState %s = %s",this.address, this.state)); @@ -1436,7 +1435,7 @@ class MHDryContact { this.log.debug(sprintf("changeMotionSensorState %s = %s",this.address, this.state)); this.LoggingService.addEntry({time: moment().unix(), status: this.state}); }); - this.dryContactService.getCharacteristic(LegrandMyHome.Duration) + this.dryContactService.getCharacteristic(Elgato.Duration) .on('set', (value, callback) => { this.duration = value; callback(null); @@ -1631,7 +1630,7 @@ class MHControlledLoad { .setCharacteristic(Characteristic.Model, "Controlled load") .setCharacteristic(Characteristic.SerialNumber, "Priority " + this.address); - this.controlledLoad = new LegrandMyHome.ControlledLoadService(this.name); + this.controlledLoad = new Elgato.ControlledLoadService(this.name); this.controlledLoad.getCharacteristic(Characteristic.Active) .on('set', (value,callback) => { From e08e996440495c96bc4d9ce09ba0a60678377850 Mon Sep 17 00:00:00 2001 From: simont77 Date: Tue, 9 Jan 2018 16:35:57 +0100 Subject: [PATCH 19/96] cleanup --- index.js | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/index.js b/index.js index d1bfa24..74a06d6 100644 --- a/index.js +++ b/index.js @@ -366,20 +366,6 @@ class LegrandMyHome { this.devices.forEach(function(accessory) { if (accessory.powerMeterService !== undefined) { accessory.value = _value; - /*accessory.totalenergy = accessory.totalenergy + _value * accessory.refresh / 3600 / 1000; - accessory.intPower = accessory.intPower + _value; - if (accessory.acquiredSamples Date: Tue, 9 Jan 2018 16:40:11 +0100 Subject: [PATCH 20/96] added firmwareRevision from package.json --- index.js | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/index.js b/index.js index 74a06d6..b33bd39 100644 --- a/index.js +++ b/index.js @@ -721,6 +721,7 @@ class MHRelay { service.setCharacteristic(Characteristic.Name, this.name) .setCharacteristic(Characteristic.Manufacturer, "Legrand MyHome") .setCharacteristic(Characteristic.Model, "Relay") + .setCharacteristic(Characteristic.FirmwareRevision, version) .setCharacteristic(Characteristic.SerialNumber, "Address " + this.address); switch (this.config.accessory) { @@ -787,6 +788,7 @@ class MHTimedRelay { service.setCharacteristic(Characteristic.Name, this.name) .setCharacteristic(Characteristic.Manufacturer, "Legrand MyHome") .setCharacteristic(Characteristic.Model, "TimedRelay") + .setCharacteristic(Characteristic.FirmwareRevision, version) .setCharacteristic(Characteristic.SerialNumber, "Address " + this.address); @@ -863,6 +865,7 @@ class MHRain { service.setCharacteristic(Characteristic.Name, this.name) .setCharacteristic(Characteristic.Manufacturer, "Legrand MyHome") .setCharacteristic(Characteristic.Model, "Relay") + .setCharacteristic(Characteristic.FirmwareRevision, version) .setCharacteristic(Characteristic.SerialNumber, "Address " + this.address); @@ -940,6 +943,7 @@ class MHBlind { service.setCharacteristic(Characteristic.Name, this.name) .setCharacteristic(Characteristic.Manufacturer, "Legrand MyHome") .setCharacteristic(Characteristic.Model, "Blind") + .setCharacteristic(Characteristic.FirmwareRevision, version) .setCharacteristic(Characteristic.SerialNumber, "Address " + this.address); this.windowCoveringService = new Service.WindowCovering(this.name); @@ -1009,6 +1013,7 @@ class MHBlindAdvanced { service.setCharacteristic(Characteristic.Name, this.name) .setCharacteristic(Characteristic.Manufacturer, "Legrand MyHome") .setCharacteristic(Characteristic.Model, "Advanced Blind") + .setCharacteristic(Characteristic.FirmwareRevision, version) .setCharacteristic(Characteristic.SerialNumber, "Address " + this.address); this.windowCoveringPlusService = new Service.WindowCovering(this.name); @@ -1077,6 +1082,7 @@ class MHDimmer { service.setCharacteristic(Characteristic.Name, this.name) .setCharacteristic(Characteristic.Manufacturer, "Legrand MyHome") .setCharacteristic(Characteristic.Model, "Dimmer") + .setCharacteristic(Characteristic.FirmwareRevision, version) .setCharacteristic(Characteristic.SerialNumber, "Address " + this.address); this.lightBulbService = new Service.Lightbulb(this.name); @@ -1135,6 +1141,7 @@ class MHThermostat { service.setCharacteristic(Characteristic.Name, this.name) .setCharacteristic(Characteristic.Manufacturer, "Legrand MyHome") .setCharacteristic(Characteristic.Model, "Thermostat") + .setCharacteristic(Characteristic.FirmwareRevision, version) .setCharacteristic(Characteristic.SerialNumber, "Address " + this.address); this.thermostatService = new Service.Thermostat(this.name); @@ -1209,6 +1216,7 @@ class MHThermometer { service.setCharacteristic(Characteristic.Name, this.name) .setCharacteristic(Characteristic.Manufacturer, "Legrand MyHome") .setCharacteristic(Characteristic.Model, "Thermometer") + .setCharacteristic(Characteristic.FirmwareRevision, version) .setCharacteristic(Characteristic.SerialNumber, "Address " + this.address); this.thermometerService = new Service.TemperatureSensor(this.name); @@ -1270,6 +1278,7 @@ class MHPowerMeter { service.setCharacteristic(Characteristic.Name, this.name) .setCharacteristic(Characteristic.Manufacturer, "Legrand MyHome") .setCharacteristic(Characteristic.Model, "Power Meter") + .setCharacteristic(Characteristic.FirmwareRevision, version) .setCharacteristic(Characteristic.SerialNumber, "Address " + this.address); this.powerMeterService = new Elgato.PowerMeterService(this.name); @@ -1314,6 +1323,7 @@ class MHButton { service.setCharacteristic(Characteristic.Name, this.name) .setCharacteristic(Characteristic.Manufacturer, "Legrand MyHome") .setCharacteristic(Characteristic.Model, "CEN/CEN+") + .setCharacteristic(Characteristic.FirmwareRevision, version) .setCharacteristic(Characteristic.SerialNumber, "Address " + this.address); this.statelessSwitch = new Service.Switch(this.name); @@ -1360,6 +1370,7 @@ class MHDryContact { service.setCharacteristic(Characteristic.Name, this.name) .setCharacteristic(Characteristic.Manufacturer, "Legrand MyHome") .setCharacteristic(Characteristic.Model, "Dry-contact Sensor") + .setCharacteristic(Characteristic.FirmwareRevision, version) .setCharacteristic(Characteristic.SerialNumber, "Address " + this.address); switch (this.type) { @@ -1467,6 +1478,7 @@ class MHAux { service.setCharacteristic(Characteristic.Name, this.name) .setCharacteristic(Characteristic.Manufacturer, "Legrand MyHome") .setCharacteristic(Characteristic.Model, "AUX") + .setCharacteristic(Characteristic.FirmwareRevision, version) .setCharacteristic(Characteristic.SerialNumber, "Address " + this.address); switch (this.type) { @@ -1545,6 +1557,7 @@ class MHAlarm { service.setCharacteristic(Characteristic.Name, this.name) .setCharacteristic(Characteristic.Manufacturer, "Legrand MyHome") .setCharacteristic(Characteristic.Model, "Alarm 3486") + .setCharacteristic(Characteristic.FirmwareRevision, version) .setCharacteristic(Characteristic.SerialNumber, "Address " + this.address); this.alarmService = new Service.SecuritySystem(this.name); @@ -1614,6 +1627,7 @@ class MHControlledLoad { service.setCharacteristic(Characteristic.Name, this.name) .setCharacteristic(Characteristic.Manufacturer, "Legrand MyHome") .setCharacteristic(Characteristic.Model, "Controlled load") + .setCharacteristic(Characteristic.FirmwareRevision, version) .setCharacteristic(Characteristic.SerialNumber, "Priority " + this.address); this.controlledLoad = new Elgato.ControlledLoadService(this.name); From 0d28207858d853827ca8c22fd0e030fd644dc019 Mon Sep 17 00:00:00 2001 From: simont77 Date: Tue, 9 Jan 2018 16:52:47 +0100 Subject: [PATCH 21/96] fix AccessoryInfo --- index.js | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/index.js b/index.js index b33bd39..0538918 100644 --- a/index.js +++ b/index.js @@ -719,7 +719,7 @@ class MHRelay { getServices() { var service = new Service.AccessoryInformation(); service.setCharacteristic(Characteristic.Name, this.name) - .setCharacteristic(Characteristic.Manufacturer, "Legrand MyHome") + .setCharacteristic(Characteristic.Manufacturer, "Simone Tisa") .setCharacteristic(Characteristic.Model, "Relay") .setCharacteristic(Characteristic.FirmwareRevision, version) .setCharacteristic(Characteristic.SerialNumber, "Address " + this.address); @@ -786,7 +786,7 @@ class MHTimedRelay { getServices() { var service = new Service.AccessoryInformation(); service.setCharacteristic(Characteristic.Name, this.name) - .setCharacteristic(Characteristic.Manufacturer, "Legrand MyHome") + .setCharacteristic(Characteristic.Manufacturer, "Simone Tisa") .setCharacteristic(Characteristic.Model, "TimedRelay") .setCharacteristic(Characteristic.FirmwareRevision, version) .setCharacteristic(Characteristic.SerialNumber, "Address " + this.address); @@ -863,7 +863,7 @@ class MHRain { getServices() { var service = new Service.AccessoryInformation(); service.setCharacteristic(Characteristic.Name, this.name) - .setCharacteristic(Characteristic.Manufacturer, "Legrand MyHome") + .setCharacteristic(Characteristic.Manufacturer, "Simone Tisa") .setCharacteristic(Characteristic.Model, "Relay") .setCharacteristic(Characteristic.FirmwareRevision, version) .setCharacteristic(Characteristic.SerialNumber, "Address " + this.address); @@ -941,7 +941,7 @@ class MHBlind { getServices() { var service = new Service.AccessoryInformation(); service.setCharacteristic(Characteristic.Name, this.name) - .setCharacteristic(Characteristic.Manufacturer, "Legrand MyHome") + .setCharacteristic(Characteristic.Manufacturer, "Simone Tisa") .setCharacteristic(Characteristic.Model, "Blind") .setCharacteristic(Characteristic.FirmwareRevision, version) .setCharacteristic(Characteristic.SerialNumber, "Address " + this.address); @@ -1011,7 +1011,7 @@ class MHBlindAdvanced { getServices() { var service = new Service.AccessoryInformation(); service.setCharacteristic(Characteristic.Name, this.name) - .setCharacteristic(Characteristic.Manufacturer, "Legrand MyHome") + .setCharacteristic(Characteristic.Manufacturer, "Simone Tisa") .setCharacteristic(Characteristic.Model, "Advanced Blind") .setCharacteristic(Characteristic.FirmwareRevision, version) .setCharacteristic(Characteristic.SerialNumber, "Address " + this.address); @@ -1080,7 +1080,7 @@ class MHDimmer { getServices() { var service = new Service.AccessoryInformation(); service.setCharacteristic(Characteristic.Name, this.name) - .setCharacteristic(Characteristic.Manufacturer, "Legrand MyHome") + .setCharacteristic(Characteristic.Manufacturer, "Simone Tisa") .setCharacteristic(Characteristic.Model, "Dimmer") .setCharacteristic(Characteristic.FirmwareRevision, version) .setCharacteristic(Characteristic.SerialNumber, "Address " + this.address); @@ -1139,7 +1139,7 @@ class MHThermostat { getServices() { var service = new Service.AccessoryInformation(); service.setCharacteristic(Characteristic.Name, this.name) - .setCharacteristic(Characteristic.Manufacturer, "Legrand MyHome") + .setCharacteristic(Characteristic.Manufacturer, "Simone Tisa") .setCharacteristic(Characteristic.Model, "Thermostat") .setCharacteristic(Characteristic.FirmwareRevision, version) .setCharacteristic(Characteristic.SerialNumber, "Address " + this.address); @@ -1214,7 +1214,7 @@ class MHThermometer { getServices() { var service = new Service.AccessoryInformation(); service.setCharacteristic(Characteristic.Name, this.name) - .setCharacteristic(Characteristic.Manufacturer, "Legrand MyHome") + .setCharacteristic(Characteristic.Manufacturer, "Simone Tisa") .setCharacteristic(Characteristic.Model, "Thermometer") .setCharacteristic(Characteristic.FirmwareRevision, version) .setCharacteristic(Characteristic.SerialNumber, "Address " + this.address); @@ -1276,10 +1276,10 @@ class MHPowerMeter { var service = new Service.AccessoryInformation(); service.setCharacteristic(Characteristic.Name, this.name) - .setCharacteristic(Characteristic.Manufacturer, "Legrand MyHome") + .setCharacteristic(Characteristic.Manufacturer, "Simone Tisa") .setCharacteristic(Characteristic.Model, "Power Meter") .setCharacteristic(Characteristic.FirmwareRevision, version) - .setCharacteristic(Characteristic.SerialNumber, "Address " + this.address); + .setCharacteristic(Characteristic.SerialNumber, "Name-" + this.name); this.powerMeterService = new Elgato.PowerMeterService(this.name); this.powerMeterService.getCharacteristic(Elgato.CurrentPowerConsumption) @@ -1321,7 +1321,7 @@ class MHButton { getServices() { var service = new Service.AccessoryInformation(); service.setCharacteristic(Characteristic.Name, this.name) - .setCharacteristic(Characteristic.Manufacturer, "Legrand MyHome") + .setCharacteristic(Characteristic.Manufacturer, "Simone Tisa") .setCharacteristic(Characteristic.Model, "CEN/CEN+") .setCharacteristic(Characteristic.FirmwareRevision, version) .setCharacteristic(Characteristic.SerialNumber, "Address " + this.address); @@ -1368,7 +1368,7 @@ class MHDryContact { getServices() { var service = new Service.AccessoryInformation(); service.setCharacteristic(Characteristic.Name, this.name) - .setCharacteristic(Characteristic.Manufacturer, "Legrand MyHome") + .setCharacteristic(Characteristic.Manufacturer, "Simone Tisa") .setCharacteristic(Characteristic.Model, "Dry-contact Sensor") .setCharacteristic(Characteristic.FirmwareRevision, version) .setCharacteristic(Characteristic.SerialNumber, "Address " + this.address); @@ -1476,7 +1476,7 @@ class MHAux { getServices() { var service = new Service.AccessoryInformation(); service.setCharacteristic(Characteristic.Name, this.name) - .setCharacteristic(Characteristic.Manufacturer, "Legrand MyHome") + .setCharacteristic(Characteristic.Manufacturer, "Simone Tisa") .setCharacteristic(Characteristic.Model, "AUX") .setCharacteristic(Characteristic.FirmwareRevision, version) .setCharacteristic(Characteristic.SerialNumber, "Address " + this.address); @@ -1555,10 +1555,10 @@ class MHAlarm { getServices() { var service = new Service.AccessoryInformation(); service.setCharacteristic(Characteristic.Name, this.name) - .setCharacteristic(Characteristic.Manufacturer, "Legrand MyHome") + .setCharacteristic(Characteristic.Manufacturer, "Simone Tisa") .setCharacteristic(Characteristic.Model, "Alarm 3486") .setCharacteristic(Characteristic.FirmwareRevision, version) - .setCharacteristic(Characteristic.SerialNumber, "Address " + this.address); + .setCharacteristic(Characteristic.SerialNumber, "Name- " + this.name); this.alarmService = new Service.SecuritySystem(this.name); this.alarmService.getCharacteristic(Characteristic.SecuritySystemCurrentState) @@ -1625,7 +1625,7 @@ class MHControlledLoad { getServices() { var service = new Service.AccessoryInformation(); service.setCharacteristic(Characteristic.Name, this.name) - .setCharacteristic(Characteristic.Manufacturer, "Legrand MyHome") + .setCharacteristic(Characteristic.Manufacturer, "Simone Tisa") .setCharacteristic(Characteristic.Model, "Controlled load") .setCharacteristic(Characteristic.FirmwareRevision, version) .setCharacteristic(Characteristic.SerialNumber, "Priority " + this.address); From 052074470e17ef7105f0f03c3d5a3aa2e460c857 Mon Sep 17 00:00:00 2001 From: simont77 Date: Tue, 9 Jan 2018 18:23:00 +0100 Subject: [PATCH 22/96] fix --- index.js | 120 +++++++++++++++++++++++++++---------------------------- 1 file changed, 60 insertions(+), 60 deletions(-) diff --git a/index.js b/index.js index 0538918..aa0d41c 100644 --- a/index.js +++ b/index.js @@ -15,7 +15,7 @@ module.exports = function (homebridge) { var FakeGatoHistoryService = require('fakegato-history')(homebridge); /* Try to map Elgato custom vars */ - Elgato.CurrentPowerConsumption = function() { + LegrandMyHome.CurrentPowerConsumption = function() { Characteristic.call(this, 'Consumption', 'E863F10D-079E-48FF-8F27-9C2605A29F52'); this.setProps({ format: Characteristic.Formats.UINT16, @@ -27,10 +27,10 @@ module.exports = function (homebridge) { }); this.value = this.getDefaultValue(); }; - Elgato.CurrentPowerConsumption.UUID = 'E863F10D-079E-48FF-8F27-9C2605A29F52'; - inherits(Elgato.CurrentPowerConsumption, Characteristic); + LegrandMyHome.CurrentPowerConsumption.UUID = 'E863F10D-079E-48FF-8F27-9C2605A29F52'; + inherits(LegrandMyHome.CurrentPowerConsumption, Characteristic); - Elgato.TotalConsumption = function() { + LegrandMyHome.TotalConsumption = function() { Characteristic.call(this, 'Energy', 'E863F10C-079E-48FF-8F27-9C2605A29F52'); this.setProps({ format: Characteristic.Formats.FLOAT, @@ -42,10 +42,10 @@ module.exports = function (homebridge) { }); this.value = this.getDefaultValue(); }; - Elgato.TotalConsumption.UUID = 'E863F10C-079E-48FF-8F27-9C2605A29F52'; - inherits(Elgato.TotalConsumption, Characteristic); + LegrandMyHome.TotalConsumption.UUID = 'E863F10C-079E-48FF-8F27-9C2605A29F52'; + inherits(LegrandMyHome.TotalConsumption, Characteristic); - Elgato.ResetTotal = function() { + LegrandMyHome.ResetTotal = function() { Characteristic.call(this, 'Reset', 'E863F112-079E-48FF-8F27-9C2605A29F52'); this.setProps({ format: Characteristic.Formats.UINT32, @@ -53,10 +53,10 @@ module.exports = function (homebridge) { }); this.value = this.getDefaultValue(); }; - Elgato.ResetTotal.UUID = 'E863F112-079E-48FF-8F27-9C2605A29F52'; - inherits(Elgato.ResetTotal, Characteristic); + LegrandMyHome.ResetTotal.UUID = 'E863F112-079E-48FF-8F27-9C2605A29F52'; + inherits(LegrandMyHome.ResetTotal, Characteristic); - Elgato.Sensitivity = function() { + LegrandMyHome.Sensitivity = function() { Characteristic.call(this, 'Sensitivity', 'E863F120-079E-48FF-8F27-9C2605A29F52'); this.setProps({ format: Characteristic.Formats.UINT16, @@ -67,10 +67,10 @@ module.exports = function (homebridge) { }); this.value = this.getDefaultValue(); }; - Elgato.Sensitivity.UUID = 'E863F120-079E-48FF-8F27-9C2605A29F52'; - inherits(Elgato.Sensitivity, Characteristic); + LegrandMyHome.Sensitivity.UUID = 'E863F120-079E-48FF-8F27-9C2605A29F52'; + inherits(LegrandMyHome.Sensitivity, Characteristic); - Elgato.Duration = function() { + LegrandMyHome.Duration = function() { Characteristic.call(this, 'Duration', 'E863F12D-079E-48FF-8F27-9C2605A29F52'); this.setProps({ format: Characteristic.Formats.UINT16, @@ -81,10 +81,10 @@ module.exports = function (homebridge) { }); this.value = this.getDefaultValue(); }; - Elgato.Duration.UUID = 'E863F12D-079E-48FF-8F27-9C2605A29F52'; - inherits(Elgato.Duration, Characteristic); + LegrandMyHome.Duration.UUID = 'E863F12D-079E-48FF-8F27-9C2605A29F52'; + inherits(LegrandMyHome.Duration, Characteristic); - Elgato.LastActivation = function() { + LegrandMyHome.LastActivation = function() { Characteristic.call(this, 'LastActivation', 'E863F11A-079E-48FF-8F27-9C2605A29F52'); this.setProps({ format: Characteristic.Formats.UINT32, @@ -92,10 +92,10 @@ module.exports = function (homebridge) { }); this.value = this.getDefaultValue(); }; - Elgato.LastActivation.UUID = 'E863F11A-079E-48FF-8F27-9C2605A29F52'; - inherits(Elgato.LastActivation, Characteristic); + LegrandMyHome.LastActivation.UUID = 'E863F11A-079E-48FF-8F27-9C2605A29F52'; + inherits(LegrandMyHome.LastActivation, Characteristic); - Elgato.TimesOpened = function() { + LegrandMyHome.TimesOpened = function() { Characteristic.call(this, 'TimesOpened', 'E863F129-079E-48FF-8F27-9C2605A29F52'); this.setProps({ format: Characteristic.Formats.UINT32, @@ -103,10 +103,10 @@ module.exports = function (homebridge) { }); this.value = this.getDefaultValue(); }; - Elgato.TimesOpened.UUID = 'E863F129-079E-48FF-8F27-9C2605A29F52'; - inherits(Elgato.TimesOpened, Characteristic); + LegrandMyHome.TimesOpened.UUID = 'E863F129-079E-48FF-8F27-9C2605A29F52'; + inherits(LegrandMyHome.TimesOpened, Characteristic); - Elgato.Char118 = function() { + LegrandMyHome.Char118 = function() { Characteristic.call(this, 'Char118', 'E863F118-079E-48FF-8F27-9C2605A29F52'); this.setProps({ format: Characteristic.Formats.UINT32, @@ -114,10 +114,10 @@ module.exports = function (homebridge) { }); this.value = this.getDefaultValue(); }; - Elgato.Char118.UUID = 'E863F118-079E-48FF-8F27-9C2605A29F52'; - inherits(Elgato.Char118, Characteristic); + LegrandMyHome.Char118.UUID = 'E863F118-079E-48FF-8F27-9C2605A29F52'; + inherits(LegrandMyHome.Char118, Characteristic); - Elgato.Char119 = function() { + LegrandMyHome.Char119 = function() { Characteristic.call(this, 'Char119', 'E863F119-079E-48FF-8F27-9C2605A29F52'); this.setProps({ format: Characteristic.Formats.UINT32, @@ -125,32 +125,32 @@ module.exports = function (homebridge) { }); this.value = this.getDefaultValue(); }; - Elgato.Char119.UUID = 'E863F119-079E-48FF-8F27-9C2605A29F52'; - inherits(Elgato.Char119, Characteristic); + LegrandMyHome.Char119.UUID = 'E863F119-079E-48FF-8F27-9C2605A29F52'; + inherits(LegrandMyHome.Char119, Characteristic); - Elgato.PowerMeterService = function(displayName, subtype) { + LegrandMyHome.PowerMeterService = function(displayName, subtype) { Service.call(this, displayName, '00000001-0000-1777-8000-775D67EC4377', subtype); - this.addCharacteristic(Elgato.CurrentPowerConsumption); - this.addCharacteristic(Elgato.TotalConsumption); - this.addCharacteristic(Elgato.ResetTotal); + this.addCharacteristic(LegrandMyHome.CurrentPowerConsumption); + this.addCharacteristic(LegrandMyHome.TotalConsumption); + this.addCharacteristic(LegrandMyHome.ResetTotal); }; - inherits(Elgato.PowerMeterService, Service); + inherits(LegrandMyHome.PowerMeterService, Service); - Elgato.FakeGatoHistoryService=FakeGatoHistoryService; - inherits(Elgato.FakeGatoHistoryService, Service); + LegrandMyHome.FakeGatoHistoryService=FakeGatoHistoryService; + inherits(LegrandMyHome.FakeGatoHistoryService, Service); - Elgato.ControlledLoadService = function(displayName, subtype) { + LegrandMyHome.ControlledLoadService = function(displayName, subtype) { Service.call(this, displayName, 'D43133F2-9BDE-4731-9FF2-B427189DCB4A', subtype); this.addCharacteristic(Characteristic.OutletInUse); this.addCharacteristic(Characteristic.Active); }; - inherits(Elgato.ControlledLoadService, Service); + inherits(LegrandMyHome.ControlledLoadService, Service); - Elgato.RainSensorService = function(displayName, subtype) { + LegrandMyHome.RainSensorService = function(displayName, subtype) { Service.call(this, displayName, '9018CDC8-DEF9-49D5-A969-63F8CCAAB1A6', subtype); this.addCharacteristic(Characteristic.CurrentRelativeHumidity); }; - inherits(Elgato.RainSensorService, Service); + inherits(LegrandMyHome.RainSensorService, Service); process.setMaxListeners(0); homebridge.registerPlatform("homebridge-myhome", "LegrandMyHome", LegrandMyHome); @@ -1260,8 +1260,8 @@ class MHPowerMeter { this.acquiredSamples=0; this.intPower=0; } - this.powerMeterService.getCharacteristic(Elgato.CurrentPowerConsumption).getValue(null); - this.powerMeterService.getCharacteristic(Elgato.TotalConsumption).getValue(null); + this.powerMeterService.getCharacteristic(LegrandMyHome.CurrentPowerConsumption).getValue(null); + this.powerMeterService.getCharacteristic(LegrandMyHome.TotalConsumption).getValue(null); this.mh.getPower(); }.bind(this), this.refresh * 1000); @@ -1281,24 +1281,24 @@ class MHPowerMeter { .setCharacteristic(Characteristic.FirmwareRevision, version) .setCharacteristic(Characteristic.SerialNumber, "Name-" + this.name); - this.powerMeterService = new Elgato.PowerMeterService(this.name); - this.powerMeterService.getCharacteristic(Elgato.CurrentPowerConsumption) + this.powerMeterService = new LegrandMyHome.PowerMeterService(this.name); + this.powerMeterService.getCharacteristic(LegrandMyHome.CurrentPowerConsumption) .on('get', (callback) => { this.log.debug(sprintf("getConsumptio = %s",this.value)); callback(null, this.value); }); - this.powerMeterService.getCharacteristic(Elgato.TotalConsumption) + this.powerMeterService.getCharacteristic(LegrandMyHome.TotalConsumption) .on('get', (callback) => { this.log.debug(sprintf("getConsumptio = %f",this.totalenergy)); callback(null, this.totalenergy); }); - this.powerMeterService.getCharacteristic(Elgato.ResetTotal) + this.powerMeterService.getCharacteristic(LegrandMyHome.ResetTotal) .on('set', (value, callback) => { this.totalenergy = 0; callback(null); }); - this.powerLoggingService = new Elgato.FakeGatoHistoryService("energy", this); + this.powerLoggingService = new LegrandMyHome.FakeGatoHistoryService("energy", this); return [service, this.powerMeterService, this.powerLoggingService]; } @@ -1376,12 +1376,12 @@ class MHDryContact { switch (this.type) { case 'Contact': this.dryContactService = new Service.ContactSensor(this.name); - this.LoggingService = new Elgato.FakeGatoHistoryService("door", this); - this.dryContactService.addCharacteristic(Elgato.LastActivation); - this.dryContactService.addCharacteristic(Elgato.TimesOpened); - this.dryContactService.addCharacteristic(Elgato.ResetTotal); - this.dryContactService.addCharacteristic(Elgato.Char118); - this.dryContactService.addCharacteristic(Elgato.Char119); + this.LoggingService = new LegrandMyHome.FakeGatoHistoryService("door", this); + this.dryContactService.addCharacteristic(LegrandMyHome.LastActivation); + this.dryContactService.addCharacteristic(LegrandMyHome.TimesOpened); + this.dryContactService.addCharacteristic(LegrandMyHome.ResetTotal); + this.dryContactService.addCharacteristic(LegrandMyHome.Char118); + this.dryContactService.addCharacteristic(LegrandMyHome.Char119); this.dryContactService.getCharacteristic(Characteristic.ContactSensorState) .on('get', (callback) => { this.log.debug(sprintf("getContactSensorState %s = %s",this.address, this.state)); @@ -1394,12 +1394,12 @@ class MHDryContact { if (this.state) this.numberOpened++; }); - this.dryContactService.getCharacteristic(Elgato.ResetTotal) + this.dryContactService.getCharacteristic(LegrandMyHome.ResetTotal) .on('set', (value, callback) => { this.numberOpened = 0; callback(null); }); - this.dryContactService.getCharacteristic(Elgato.TimesOpened) + this.dryContactService.getCharacteristic(LegrandMyHome.TimesOpened) .on('get', (callback) => { this.log.debug(sprintf("getNumberOpened = %f",this.numberOpened)); callback(null, this.numberOpened); @@ -1417,11 +1417,11 @@ class MHDryContact { break; case 'Motion': this.dryContactService = new Service.MotionSensor(this.name); - this.LoggingService = new Elgato.FakeGatoHistoryService("motion", this); - this.dryContactService.addCharacteristic(Elgato.Sensitivity); - this.dryContactService.addCharacteristic(Elgato.Duration); - this.dryContactService.addCharacteristic(Elgato.LastActivation); - this.dryContactService.setCharacteristic(Elgato.Duration,this.duration); + this.LoggingService = new LegrandMyHome.FakeGatoHistoryService("motion", this); + this.dryContactService.addCharacteristic(LegrandMyHome.Sensitivity); + this.dryContactService.addCharacteristic(LegrandMyHome.Duration); + this.dryContactService.addCharacteristic(LegrandMyHome.LastActivation); + this.dryContactService.setCharacteristic(LegrandMyHome.Duration,this.duration); this.dryContactService.getCharacteristic(Characteristic.MotionDetected) .on('get', (callback) => { this.log.debug(sprintf("getMotionSensorState %s = %s",this.address, this.state)); @@ -1432,7 +1432,7 @@ class MHDryContact { this.log.debug(sprintf("changeMotionSensorState %s = %s",this.address, this.state)); this.LoggingService.addEntry({time: moment().unix(), status: this.state}); }); - this.dryContactService.getCharacteristic(Elgato.Duration) + this.dryContactService.getCharacteristic(LegrandMyHome.Duration) .on('set', (value, callback) => { this.duration = value; callback(null); @@ -1630,7 +1630,7 @@ class MHControlledLoad { .setCharacteristic(Characteristic.FirmwareRevision, version) .setCharacteristic(Characteristic.SerialNumber, "Priority " + this.address); - this.controlledLoad = new Elgato.ControlledLoadService(this.name); + this.controlledLoad = new LegrandMyHome.ControlledLoadService(this.name); this.controlledLoad.getCharacteristic(Characteristic.Active) .on('set', (value,callback) => { From e21a6851ed5208be1fe2e0c39310a05059dab01e Mon Sep 17 00:00:00 2001 From: simont77 Date: Tue, 9 Jan 2018 18:25:01 +0100 Subject: [PATCH 23/96] update dependencies --- package.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index f5cb0ab..3f99aa9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-myhome-tng", - "version": "0.1.2", + "version": "0.1.3", "description": "Legrand MyHome plugin for homebridge: https://github.com/nfarina/homebridge", "license": "MIT", "keywords": [ @@ -11,7 +11,7 @@ "homebridge": ">=0.2.0" }, "author": { - "name": "Angelo Conforti and Simone Tisa" + "name": "Simone Tisa" }, "repository": { "type": "git", @@ -30,6 +30,6 @@ "inherits": "^2.0.0", "moment": "^2.18.1", "correcting-interval":"^2.0.0", - "fakegato-history":"^0.3.2" + "fakegato-history":"^0.3.4" } } From 8bfc5b0b3d0dfe1bbdfbea0eafa507fba8246933 Mon Sep 17 00:00:00 2001 From: Simone Tisa Date: Sun, 14 Jan 2018 11:53:42 +0100 Subject: [PATCH 24/96] add entry on startup in motion and door --- index.js | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/index.js b/index.js index aa0d41c..0a39c00 100644 --- a/index.js +++ b/index.js @@ -1354,7 +1354,8 @@ class MHDryContact { this.type = config.type; this.numberOpened = 0; this.durationhandle = null; - this.duration = 30; + this.duration = config.duration || 30; + this.firstGet = true; this.state = config.state || false; this.log.info(sprintf("LegrandMyHome::MHDryContact create object: %s", this.address)); @@ -1385,6 +1386,10 @@ class MHDryContact { this.dryContactService.getCharacteristic(Characteristic.ContactSensorState) .on('get', (callback) => { this.log.debug(sprintf("getContactSensorState %s = %s",this.address, this.state)); + if (this.firstGet) { + this.firstGet = false; + this.LoggingService.addEntry({time: moment().unix(), status: this.state}); + } callback(null, this.state); }); this.dryContactService.getCharacteristic(Characteristic.ContactSensorState) @@ -1425,6 +1430,10 @@ class MHDryContact { this.dryContactService.getCharacteristic(Characteristic.MotionDetected) .on('get', (callback) => { this.log.debug(sprintf("getMotionSensorState %s = %s",this.address, this.state)); + if (this.firstGet) { + this.firstGet = false; + this.LoggingService.addEntry({time: moment().unix(), status: this.state}); + } callback(null, this.state); }); this.dryContactService.getCharacteristic(Characteristic.MotionDetected) From d08dd1e522d40e3a70a64278b626416548b7429f Mon Sep 17 00:00:00 2001 From: simont77 Date: Tue, 16 Jan 2018 14:06:34 +0100 Subject: [PATCH 25/96] update dependencies --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 3f99aa9..1c4b694 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,6 @@ "inherits": "^2.0.0", "moment": "^2.18.1", "correcting-interval":"^2.0.0", - "fakegato-history":"^0.3.4" + "fakegato-history":"^0.3.6" } } From c06ee5ecad9c01c8037d4f9e0feec68ef38b46a4 Mon Sep 17 00:00:00 2001 From: Simone Tisa Date: Sat, 20 Jan 2018 15:26:50 +0100 Subject: [PATCH 26/96] added last detection in motion and door --- index.js | 18 ++++++++++++++++-- package.json | 4 ++-- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/index.js b/index.js index 0a39c00..5a41be4 100644 --- a/index.js +++ b/index.js @@ -1356,7 +1356,7 @@ class MHDryContact { this.durationhandle = null; this.duration = config.duration || 30; this.firstGet = true; - + this.lastOpening = 0; this.state = config.state || false; this.log.info(sprintf("LegrandMyHome::MHDryContact create object: %s", this.address)); } @@ -1388,7 +1388,8 @@ class MHDryContact { this.log.debug(sprintf("getContactSensorState %s = %s",this.address, this.state)); if (this.firstGet) { this.firstGet = false; - this.LoggingService.addEntry({time: moment().unix(), status: this.state}); + this.LoggingService.addEntry({time: moment().unix(), status: this.state}); + this.offset = moment().unix(); } callback(null, this.state); }); @@ -1396,6 +1397,7 @@ class MHDryContact { .on('change', () => { this.log.debug(sprintf("changeContactSensorState %s = %s",this.address, this.state)); this.LoggingService.addEntry({time: moment().unix(), status: this.state}); + this.lastOpening = moment().unix()-this.offset; if (this.state) this.numberOpened++; }); @@ -1409,6 +1411,11 @@ class MHDryContact { this.log.debug(sprintf("getNumberOpened = %f",this.numberOpened)); callback(null, this.numberOpened); }); + this.dryContactService.getCharacteristic(LegrandMyHome.LastActivation) + .on('get', (callback) => { + this.log.debug(sprintf("lastOpening = %f",this.lastOpening)); + callback(null, this.lastOpening); + }); return [service, this.dryContactService, this.LoggingService]; break; case 'Leak': @@ -1432,6 +1439,7 @@ class MHDryContact { this.log.debug(sprintf("getMotionSensorState %s = %s",this.address, this.state)); if (this.firstGet) { this.firstGet = false; + this.offset = moment().unix(); this.LoggingService.addEntry({time: moment().unix(), status: this.state}); } callback(null, this.state); @@ -1440,6 +1448,7 @@ class MHDryContact { .on('change', () => { this.log.debug(sprintf("changeMotionSensorState %s = %s",this.address, this.state)); this.LoggingService.addEntry({time: moment().unix(), status: this.state}); + this.lastOpening = moment().unix()-this.offset; }); this.dryContactService.getCharacteristic(LegrandMyHome.Duration) .on('set', (value, callback) => { @@ -1449,6 +1458,11 @@ class MHDryContact { .on('get', (callback) => { callback(null, this.duration); }); + this.dryContactService.getCharacteristic(LegrandMyHome.LastActivation) + .on('get', (callback) => { + this.log.debug(sprintf("lastOpening = %f",this.lastOpening)); + callback(null, this.lastOpening); + }); return [service, this.dryContactService, this.LoggingService]; break; diff --git a/package.json b/package.json index 1c4b694..47e6be9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-myhome-tng", - "version": "0.1.3", + "version": "0.1.4", "description": "Legrand MyHome plugin for homebridge: https://github.com/nfarina/homebridge", "license": "MIT", "keywords": [ @@ -30,6 +30,6 @@ "inherits": "^2.0.0", "moment": "^2.18.1", "correcting-interval":"^2.0.0", - "fakegato-history":"^0.3.6" + "fakegato-history":"^0.3.7" } } From 471ec1d30b70fce90ab013afb80bbd6c36200a44 Mon Sep 17 00:00:00 2001 From: simont77 Date: Tue, 23 Jan 2018 08:50:13 +0100 Subject: [PATCH 27/96] update dependencies --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 47e6be9..eabb300 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-myhome-tng", - "version": "0.1.4", + "version": "0.1.5", "description": "Legrand MyHome plugin for homebridge: https://github.com/nfarina/homebridge", "license": "MIT", "keywords": [ @@ -30,6 +30,6 @@ "inherits": "^2.0.0", "moment": "^2.18.1", "correcting-interval":"^2.0.0", - "fakegato-history":"^0.3.7" + "fakegato-history":"^0.3.8" } } From f964b4eebc2da3086c3256f8ee309c4fb27ed309 Mon Sep 17 00:00:00 2001 From: simont77 Date: Wed, 24 Jan 2018 12:37:02 +0100 Subject: [PATCH 28/96] caching reset time for door and motion --- index.js | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/index.js b/index.js index 5a41be4..4116dea 100644 --- a/index.js +++ b/index.js @@ -1359,6 +1359,7 @@ class MHDryContact { this.lastOpening = 0; this.state = config.state || false; this.log.info(sprintf("LegrandMyHome::MHDryContact create object: %s", this.address)); + this.cacheFilename = path.join(config.parent.api.user.cachedAccessoryPath(),this.displayName+'.json'); } identify(callback) { @@ -1389,7 +1390,15 @@ class MHDryContact { if (this.firstGet) { this.firstGet = false; this.LoggingService.addEntry({time: moment().unix(), status: this.state}); - this.offset = moment().unix(); + if (fs.existsSync(this.cacheFilename)) + { + this.offset = JSON.parse(fs.readFileSync(this.cacheFilename)); + } + else + { + this.offset = moment().unix(); + fs.writeFileSync(this.cacheFilename,JSON.stringify(this.offset)); + } } callback(null, this.state); }); @@ -1439,8 +1448,16 @@ class MHDryContact { this.log.debug(sprintf("getMotionSensorState %s = %s",this.address, this.state)); if (this.firstGet) { this.firstGet = false; - this.offset = moment().unix(); - this.LoggingService.addEntry({time: moment().unix(), status: this.state}); + this.LoggingService.addEntry({time: moment().unix(), status: this.state}); + if (fs.existsSync(this.cacheFilename)) + { + this.offset = JSON.parse(fs.readFileSync(this.cacheFilename)); + } + else + { + this.offset = moment().unix(); + fs.writeFileSync(this.cacheFilename,JSON.stringify(this.offset)); + } } callback(null, this.state); }); From 712880f4cddee70ba57b85d147ae37f50c3df09e Mon Sep 17 00:00:00 2001 From: Simone Tisa Date: Sat, 27 Jan 2018 20:54:01 +0100 Subject: [PATCH 29/96] fix motion update state and added fakegatoStorage --- index.js | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/index.js b/index.js index 4116dea..f3e6d0c 100644 --- a/index.js +++ b/index.js @@ -291,16 +291,23 @@ class LegrandMyHome { if (_state==true) { accessory.state = true; - accessory.dryContactService.getCharacteristic(Characteristic.MotionDetected).getValue(null); + accessory.dryContactService.getCharacteristic(Characteristic.MotionDetected).getValue(null); clearTimeout(accessory.durationhandle); accessory.durationhandle = setTimeout(function() { accessory.state = false; - accessory.dryContactService.getCharacteristic(Characteristic.MotionDetected).getValue(null); + accessory.dryContactService.getCharacteristic(Characteristic.MotionDetected).getValue(null); }.bind(this), accessory.duration * 1000); } + else + if (accessory.firstGet == true) + { + accessory.state = _state; + accessory.dryContactService.getCharacteristic(Characteristic.MotionDetected).getValue(null); + } break; default: - accessory.state = _state; accessory.dryContactService.getCharacteristic(Characteristic.ContactSensorState).getValue(null); + accessory.state = _state; + accessory.dryContactService.getCharacteristic(Characteristic.ContactSensorState).getValue(null); break; } } @@ -1298,7 +1305,8 @@ class MHPowerMeter { callback(null); }); - this.powerLoggingService = new LegrandMyHome.FakeGatoHistoryService("energy", this); + //this.powerLoggingService = new LegrandMyHome.FakeGatoHistoryService("energy", this,{storage: 'fs', path: this.config.parent.api.user.cachedAccessoryPath()}); + this.powerLoggingService = new LegrandMyHome.FakeGatoHistoryService("energy", this,{storage: 'googleDrive', path: 'homebridge'}); return [service, this.powerMeterService, this.powerLoggingService]; } @@ -1359,7 +1367,7 @@ class MHDryContact { this.lastOpening = 0; this.state = config.state || false; this.log.info(sprintf("LegrandMyHome::MHDryContact create object: %s", this.address)); - this.cacheFilename = path.join(config.parent.api.user.cachedAccessoryPath(),this.displayName+'.json'); + this.cacheFilename = path.join(this.config.parent.api.user.cachedAccessoryPath(),this.displayName+'.json'); } identify(callback) { @@ -1378,7 +1386,8 @@ class MHDryContact { switch (this.type) { case 'Contact': this.dryContactService = new Service.ContactSensor(this.name); - this.LoggingService = new LegrandMyHome.FakeGatoHistoryService("door", this); + //this.LoggingService = new LegrandMyHome.FakeGatoHistoryService("door", this,{storage: 'fs', path: this.config.parent.api.user.cachedAccessoryPath()}); + this.LoggingService = new LegrandMyHome.FakeGatoHistoryService("door", this,{storage: 'googleDrive', path: 'homebridge'}); this.dryContactService.addCharacteristic(LegrandMyHome.LastActivation); this.dryContactService.addCharacteristic(LegrandMyHome.TimesOpened); this.dryContactService.addCharacteristic(LegrandMyHome.ResetTotal); @@ -1438,7 +1447,8 @@ class MHDryContact { break; case 'Motion': this.dryContactService = new Service.MotionSensor(this.name); - this.LoggingService = new LegrandMyHome.FakeGatoHistoryService("motion", this); + //this.LoggingService = new LegrandMyHome.FakeGatoHistoryService("motion", this,{storage: 'fs', path: this.config.parent.api.user.cachedAccessoryPath()}); + this.LoggingService = new LegrandMyHome.FakeGatoHistoryService("motion", this,{storage: 'googleDrive', path: 'homebridge'}); this.dryContactService.addCharacteristic(LegrandMyHome.Sensitivity); this.dryContactService.addCharacteristic(LegrandMyHome.Duration); this.dryContactService.addCharacteristic(LegrandMyHome.LastActivation); From 41ece03fbf101fc0e89753d442e843e78840eb34 Mon Sep 17 00:00:00 2001 From: simont77 Date: Mon, 29 Jan 2018 11:08:46 +0100 Subject: [PATCH 30/96] jslint validation --- index.js | 55 ++++++++++++++++++++--------------------- lib/mhclient.js | 65 +++++++++++++++++++++++++------------------------ 2 files changed, 59 insertions(+), 61 deletions(-) diff --git a/index.js b/index.js index f3e6d0c..c4ed5d6 100644 --- a/index.js +++ b/index.js @@ -1,3 +1,4 @@ +/*jshint esversion: 6,node: true,-W041: false */ var path = require("path"); var mh = require(path.join(__dirname,'/lib/mhclient')); var sprintf = require("sprintf-js").sprintf, inherits = require("util").inherits, Promise = require('promise'); @@ -169,23 +170,23 @@ class LegrandMyHome { this.config.devices.forEach(function (accessory) { this.log.info("LegrandMyHome: adds accessory"); accessory.parent = this; - if (accessory.accessory == 'MHRelay') this.devices.push(new MHRelay(this.log,accessory)) - if (accessory.accessory == 'MHBlind') this.devices.push(new MHBlind(this.log,accessory)) - if (accessory.accessory == 'MHBlindAdvanced') this.devices.push(new MHBlindAdvanced(this.log,accessory)) - if (accessory.accessory == 'MHOutlet') this.devices.push(new MHRelay(this.log,accessory)) - if (accessory.accessory == 'MHTimedRelay') this.devices.push(new MHTimedRelay(this.log,accessory)) - if (accessory.accessory == 'MHRain') this.devices.push(new MHRain(this.log,accessory)) - if (accessory.accessory == 'MHDimmer') this.devices.push(new MHDimmer(this.log,accessory)) - if (accessory.accessory == 'MHThermostat') this.devices.push(new MHThermostat(this.log,accessory)) - if (accessory.accessory == 'MHExternalThermometer') this.devices.push(new MHThermometer(this.log,accessory)) + if (accessory.accessory == 'MHRelay') this.devices.push(new MHRelay(this.log,accessory)); + if (accessory.accessory == 'MHBlind') this.devices.push(new MHBlind(this.log,accessory)); + if (accessory.accessory == 'MHBlindAdvanced') this.devices.push(new MHBlindAdvanced(this.log,accessory)); + if (accessory.accessory == 'MHOutlet') this.devices.push(new MHRelay(this.log,accessory)); + if (accessory.accessory == 'MHTimedRelay') this.devices.push(new MHTimedRelay(this.log,accessory)); + if (accessory.accessory == 'MHRain') this.devices.push(new MHRain(this.log,accessory)); + if (accessory.accessory == 'MHDimmer') this.devices.push(new MHDimmer(this.log,accessory)); + if (accessory.accessory == 'MHThermostat') this.devices.push(new MHThermostat(this.log,accessory)); + if (accessory.accessory == 'MHExternalThermometer') this.devices.push(new MHThermometer(this.log,accessory)); - if (accessory.accessory == 'MHDryContact') this.devices.push(new MHDryContact(this.log,accessory)) - if (accessory.accessory == 'MHAux') this.devices.push(new MHAux(this.log,accessory)) + if (accessory.accessory == 'MHDryContact') this.devices.push(new MHDryContact(this.log,accessory)); + if (accessory.accessory == 'MHAux') this.devices.push(new MHAux(this.log,accessory)); /* if (accessory.accessory == 'MHButton') this.devices.push(new MHButton(this.log,accessory)) */ - if (accessory.accessory == 'MHPowerMeter') this.devices.push(new MHPowerMeter(this.log,accessory)) - if (accessory.accessory == 'MHAlarm') this.devices.push(new MHAlarm(this.log,accessory)) - if (accessory.accessory == 'MHControlledLoad') this.devices.push(new MHControlledLoad(this.log,accessory)) + if (accessory.accessory == 'MHPowerMeter') this.devices.push(new MHPowerMeter(this.log,accessory)); + if (accessory.accessory == 'MHAlarm') this.devices.push(new MHAlarm(this.log,accessory)); + if (accessory.accessory == 'MHControlledLoad') this.devices.push(new MHControlledLoad(this.log,accessory)); }.bind(this)); this.log.info("LegrandMyHome for MyHome Gateway at " + config.ipaddress + ":" + config.port); this.controller.start(); @@ -755,7 +756,7 @@ class MHRelay { } else if (!this.power && this.config.frame_off != null) { this.mh.send(this.config.frame_off); } else { - this.mh.relayCommand(this.address,this.power) + this.mh.relayCommand(this.address,this.power); } callback(null); }) @@ -823,7 +824,7 @@ class MHTimedRelay { } else { - this.mh.relayCommand(this.address,this.power) + this.mh.relayCommand(this.address,this.power); } callback(null); }) @@ -920,19 +921,19 @@ class MHBlind { if (this.runningDirection == Characteristic.PositionState.STOPPED && this.state != Characteristic.PositionState.STOPPED) { this.runningStartTime = new Date(); this.runningDirection = this.state; - this.log.debug(sprintf("Starting position is %d", this.currentPosition)) + this.log.debug(sprintf("Starting position is %d", this.currentPosition)); } else { if (this.runningDirection != Characteristic.PositionState.STOPPED && this.state == Characteristic.PositionState.STOPPED) { if (this.runningDirection == Characteristic.PositionState.INCREASING) { - this.currentPosition = Math.min(100,this.currentPosition + (100 / (this.time*1000) * (((new Date())-this.runningStartTime+this.startDelayMs)*(1+this.timeAdjust/100)))) + this.currentPosition = Math.min(100,this.currentPosition + (100 / (this.time*1000) * (((new Date())-this.runningStartTime+this.startDelayMs)*(1+this.timeAdjust/100)))); } else { - this.currentPosition = Math.max(0,this.currentPosition - (100 / (this.time*1000) * (((new Date())-this.runningStartTime+this.startDelayMs)*(1+this.timeAdjust/100)))) + this.currentPosition = Math.max(0,this.currentPosition - (100 / (this.time*1000) * (((new Date())-this.runningStartTime+this.startDelayMs)*(1+this.timeAdjust/100)))); } this.runningDirection = this.state; this.targetPosition = this.currentPosition; this.runningStartTime = -1; - this.log.debug(sprintf("Ending position is %d", this.currentPosition)) + this.log.debug(sprintf("Ending position is %d", this.currentPosition)); } else { /* Uhm... */ } @@ -1101,7 +1102,7 @@ class MHDimmer { if (this.power && this.bri == 0) { this.bri = 100; } - this.mh.relayCommand(this.address,this.power) + this.mh.relayCommand(this.address,this.power); callback(null); }) .on('get', (callback) => { @@ -1114,7 +1115,7 @@ class MHDimmer { this.log.debug(sprintf("setBrightness %s = %d",this.address, level)); this.bri = parseInt(level); this.power = (this.bri > 0); - this.mh.dimmerCommand(this.address,this.bri) + this.mh.dimmerCommand(this.address,this.bri); callback(null); }) .on('get', (callback) => { @@ -1247,8 +1248,8 @@ class MHPowerMeter { this.log = log; this.refresh = config.refresh || 15; - this.intPower = 0 - this.acquiredSamples = 0 + this.intPower = 0; + this.acquiredSamples = 0; this.averagedSampleForHistory = 600/this.refresh; this.value = 0; @@ -1435,7 +1436,6 @@ class MHDryContact { callback(null, this.lastOpening); }); return [service, this.dryContactService, this.LoggingService]; - break; case 'Leak': this.dryContactService = new Service.LeakSensor(this.name); this.dryContactService.getCharacteristic(Characteristic.LeakDetected) @@ -1444,7 +1444,6 @@ class MHDryContact { callback(null, this.state); }); return [service, this.dryContactService]; - break; case 'Motion': this.dryContactService = new Service.MotionSensor(this.name); //this.LoggingService = new LegrandMyHome.FakeGatoHistoryService("motion", this,{storage: 'fs', path: this.config.parent.api.user.cachedAccessoryPath()}); @@ -1492,7 +1491,6 @@ class MHDryContact { }); return [service, this.dryContactService, this.LoggingService]; - break; default: this.dryContactService = new Service.ContactSensor(this.name); this.dryContactService.getCharacteristic(Characteristic.ContactSensorState) @@ -1501,7 +1499,6 @@ class MHDryContact { callback(null, this.state); }); return [service, this.dryContactService]; - break; } @@ -1624,7 +1621,7 @@ class MHAlarm { .on('set', (value,callback) => { this.log.debug(sprintf("alarm set target= %d", this.target)); callback(null); - }) + }); this.alarmService.getCharacteristic(Characteristic.StatusFault) .on('get', (callback) => { this.log.debug(sprintf("getConsumptio = %s",this.value)); diff --git a/lib/mhclient.js b/lib/mhclient.js index a370004..1b82ae2 100755 --- a/lib/mhclient.js +++ b/lib/mhclient.js @@ -1,4 +1,5 @@ -const debug = require('debug')('myhomeclient') +/*jshint esversion: 6,node: true,-W041: false */ +const debug = require('debug')('myhomeclient'); const sprintf = require("sprintf-js").sprintf; const net = require('net'); const crypto = require('crypto'); @@ -80,9 +81,9 @@ class MyHomeClient { } _addressToSlashes(_address) { - if (_address.length == 4) return sprintf("0/%d/%d", parseInt(_address.substring(0,2)),parseInt(_address.substring(2,4))) - if (_address.length == 2) return sprintf("0/%d/%d", parseInt(_address.substring(0,1)),parseInt(_address.substring(1,2))) - if (_address.length == 1) return sprintf("0/%d/0", parseInt(_address)) + if (_address.length == 4) return sprintf("0/%d/%d", parseInt(_address.substring(0,2)),parseInt(_address.substring(2,4))); + if (_address.length == 2) return sprintf("0/%d/%d", parseInt(_address.substring(0,1)),parseInt(_address.substring(1,2))); + if (_address.length == 1) return sprintf("0/%d/0", parseInt(_address)); // TODO return "9/99/99"; } @@ -196,7 +197,7 @@ class MyHomeClient { /* Light level */ extract = frame.match(/^\*1\*(\d+)\*([0-9#]+)$/); if (extract) { - var address = this._addressToSlashes(extract[2]); + let address = this._addressToSlashes(extract[2]); if (extract[1] <= 1) { if (this.parent != null && this.parent.onMonitor != null && typeof(this.parent.onRelay) == 'function') this.parent.onRelay(address,extract[1] == 1); debug(sprintf("LIGHTLEVEL %s ADDRESS %s",extract[1],address)); @@ -211,7 +212,7 @@ class MyHomeClient { // *#1*12*1*190*1##> extract = frame.match(/^\*#1\*([0-9#]+)\*\d\*(\d+)\*\d+$/); if (extract) { - var address = this._addressToSlashes(extract[1]); + let address = this._addressToSlashes(extract[1]); if (this.parent != null && this.parent.onMonitor != null && typeof(this.parent.onDimmer) == 'function') this.parent.onDimmer(address,parseInt(extract[2],10)-100); } @@ -219,7 +220,7 @@ class MyHomeClient { /* Simple (F411) Blind */ extract = frame.match(/^\*2\*(\d)\*([0-9#]+)$/); if (extract) { - var address = this._addressToSlashes(extract[2]); + let address = this._addressToSlashes(extract[2]); debug(sprintf("BLIND %s ADDRESS %s",extract[1],address)); if (this.parent != null && this.parent.onMonitor != null && typeof(this.parent.onSimpleBlind) == 'function') this.parent.onSimpleBlind(address,parseInt(extract[1],10)); } @@ -227,9 +228,9 @@ class MyHomeClient { /* Advanced (F401) Blind (on stop) */ extract = frame.match(/^\*#2\*([0-9#]+)\*10\*(\d+)\*(\d+)\*\d+\*\d+$/); if (extract) { - var address = this._addressToSlashes(extract[1]); - var position = parseInt(extract[3],10); - var direction = "STOP"; + let address = this._addressToSlashes(extract[1]); + let position = parseInt(extract[3],10); + let direction = "STOP"; if (parseInt(extract[2],10) == 11) direction = "UP"; if (parseInt(extract[2],10) == 12) direction = "DOWN"; @@ -241,8 +242,8 @@ class MyHomeClient { /* Ambient temperature */ extract = frame.match(/^\*#4\*(\d+)\*[0|14]\*(\d\d\d\d)$/); if (extract) { - var address = parseInt(extract[1]); - var temperature = parseFloat(extract[2]/10); + let address = parseInt(extract[1]); + let temperature = parseFloat(extract[2]/10); if (temperature > 100) { temperature = -(temperature - 100); } @@ -253,8 +254,8 @@ class MyHomeClient { /* Setpoint temperature */ extract = frame.match(/^\*#4\*(\d+)\*12\*(\d\d\d\d)\*(\d+)$/); if (extract) { - var address = parseInt(extract[1]); - var temperature = parseFloat(extract[2]/10); + let address = parseInt(extract[1]); + let temperature = parseFloat(extract[2]/10); if (temperature > 100) { temperature = -(temperature - 100); } @@ -266,8 +267,8 @@ class MyHomeClient { // Format *#4*
00*15*1**0001## extract = frame.match(/^\*#4\*(\d+)00\*15\*1\*(\d\d\d\d)\*0001$/); if (extract) { - var address = parseInt(extract[1]); - var temperature = parseFloat(extract[2]/10); + let address = parseInt(extract[1]); + let temperature = parseFloat(extract[2]/10); if (temperature > 100) { temperature = -(temperature - 100); } @@ -278,9 +279,9 @@ class MyHomeClient { // new regex:thActuators = RegEx_Create( \"^\*#4\*(\d{1,2})\*19\*(\d)\*(\d)$" ); extract = frame.match(/^\*#4\*(\d+)\*19\*(\d)\*(\d)$/); if (extract) { - var address = parseInt(extract[1]); - var cooling = inArray(extract[2],[1,2]); - var heating = inArray(extract[3],[1,2]); + let address = parseInt(extract[1]); + let cooling = inArray(extract[2],[1,2]); + let heating = inArray(extract[3],[1,2]); if (this.parent != null && this.parent.onMonitor != null && typeof(this.parent.onThermostat) == 'function') this.parent.onThermostat(address,"HEATING",heating); if (this.parent != null && this.parent.onMonitor != null && typeof(this.parent.onThermostat) == 'function') this.parent.onThermostat(address,"COOLING",cooling); debug(sprintf("HEATING %s COOLING %s ADDRESS %s",heating,cooling,address)); @@ -297,8 +298,8 @@ class MyHomeClient { // *25*32#[0-1]*3## -> Open (0 after a state request, 1 after an event) -> FALSE extract = frame.match(/^\*25\*3(\d)#[0-1]\*3(\d+)$/); if (extract) { - var value = parseInt(extract[1],10) == 1 ? true : false; - var address = parseInt(extract[2],10); + let value = parseInt(extract[1],10) == 1 ? true : false; + let address = parseInt(extract[2],10); if (this.parent != null && this.parent.onMonitor != null && typeof(this.parent.onDryContact) == 'function') this.parent.onDryContact(address,value); debug(sprintf("DRYCONTACT %s ADDRESS %s",value,address)); } @@ -306,12 +307,12 @@ class MyHomeClient { // AUX: *9*1*## ON extract = frame.match(/^\*9\*(\d)\*(\d)$/); if (extract) { - var value = false; + let value = false; if (parseInt(extract[1],10) == 0 || parseInt(extract[1],10)==9) value = false; else value = true; - var address = parseInt(extract[2],10); + let address = parseInt(extract[2],10); if (this.parent != null && this.parent.onMonitor != null && typeof(this.parent.onAUX) == 'function') this.parent.onAUX(address,value); debug(sprintf("AUX %s ADDRESS %s",value,address)); @@ -320,7 +321,7 @@ class MyHomeClient { //powermeter extract = frame.match(/^\*#3\*10\*3\*(\d+)$/); if (extract) { - var value = parseInt(extract[1],10); + let value = parseInt(extract[1],10); if (this.parent != null && this.parent.onMonitor != null && typeof(this.parent.onPowerMeter) == 'function') this.parent.onPowerMeter(value); debug(sprintf("Power %s W",value)); @@ -330,8 +331,8 @@ class MyHomeClient { //controlled load extract = frame.match(/^\*3\*(\d)\*#(\d)$/); if (extract) { - var value = parseInt(extract[1],10); - var address = parseInt(extract[2],10); + let value = parseInt(extract[1],10); + let address = parseInt(extract[2],10); if (this.parent != null && this.parent.onMonitor != null && typeof(this.parent.onControlledLoad) == 'function') this.parent.onControlledLoad(address,value); } @@ -339,7 +340,7 @@ class MyHomeClient { //alarm status extract = frame.match(/^\*5\*(\d+)\*0*$/); if (extract) { - var value = parseInt(extract[1],10); + let value = parseInt(extract[1],10); switch (value){ case 0: @@ -382,7 +383,7 @@ class MyHomeClient { //alarm triggered and zone selection extract = frame.match(/^\*5\*(\d+)\*#(\d)$/); if (extract) { - var value = parseInt(extract[1],10); + let value = parseInt(extract[1],10); switch (value){ case 11: //zone active if (this.parent != null && this.parent.onMonitor != null && typeof(this.parent.onZoneActive) == 'function') @@ -502,7 +503,7 @@ class MyHomeConnection { }.bind(this), this.idleSeconds * 1000); var data = _in.toString().trim(); - debug('Received[%s]: <%s>', this.type, data) + debug('Received[%s]: <%s>', this.type, data); if (this.state == 0 && data == "*#*1##") { /* * Great, answers and is ready to talk with me, I send @@ -586,7 +587,7 @@ class MyHomeConnection { this.reconnecthandle = setTimeout(function() { debug('Info[%s]: Try to reconnect !', this.type); this.connect(); - }.bind(this), this.reconnectSeconds * 1000) + }.bind(this), this.reconnectSeconds * 1000); }); this.connection.on('error', (_error) => { @@ -596,7 +597,7 @@ class MyHomeConnection { this.reconnecthandle = setTimeout(function() { debug('Info[%s]: Try to reconnect !', this.type); this.connect(); - }.bind(this), this.reconnectSeconds * 1000) + }.bind(this), this.reconnectSeconds * 1000); }); } @@ -604,7 +605,7 @@ class MyHomeConnection { * OWN Password implementation that can be found on the web, it seems to work */ openwebnetAnswer(pass,nonce) { - var _0x9148=["\x30","\x31","\x32","\x33","\x34","\x35","\x36","\x37","\x38","\x39"];var _0xba8b=[_0x9148[0],_0x9148[1],_0x9148[2],_0x9148[3],_0x9148[4],_0x9148[5],_0x9148[6],_0x9148[7],_0x9148[8],_0x9148[9]];var flag=true;var num1=0x0;var num2=0x0;var password=parseInt(pass,10);for(var c in nonce){c= nonce[c];if(c!= _0xba8b[0]){if(flag){num2= password};flag= false};switch(c){case _0xba8b[1]:num1= num2& 0xFFFFFF80;num1= num1>>> 7;num2= num2<< 25;num1= num1+ num2;break;case _0xba8b[2]:num1= num2& 0xFFFFFFF0;num1= num1>>> 4;num2= num2<< 28;num1= num1+ num2;break;case _0xba8b[3]:num1= num2& 0xFFFFFFF8;num1= num1>>> 3;num2= num2<< 29;num1= num1+ num2;break;case _0xba8b[4]:num1= num2<< 1;num2= num2>>> 31;num1= num1+ num2;break;case _0xba8b[5]:num1= num2<< 5;num2= num2>>> 27;num1= num1+ num2;break;case _0xba8b[6]:num1= num2<< 12;num2= num2>>> 20;num1= num1+ num2;break;case _0xba8b[7]:num1= num2& 0x0000FF00;num1= num1+ ((num2& 0x000000FF)<< 24);num1= num1+ ((num2& 0x00FF0000)>>> 16);num2= (num2& 0xFF000000)>>> 8;num1= num1+ num2;break;case _0xba8b[8]:num1= num2& 0x0000FFFF;num1= num1<< 16;num1= num1+ (num2>>> 24);num2= num2& 0x00FF0000;num2= num2>>> 8;num1= num1+ num2;break;case _0xba8b[9]:num1= ~num2;break;case _0xba8b[0]:num1= num2;break};num2= num1};return (num1>>> 0).toString() + var _0x9148=["\x30","\x31","\x32","\x33","\x34","\x35","\x36","\x37","\x38","\x39"];var _0xba8b=[_0x9148[0],_0x9148[1],_0x9148[2],_0x9148[3],_0x9148[4],_0x9148[5],_0x9148[6],_0x9148[7],_0x9148[8],_0x9148[9]];var flag=true;var num1=0x0;var num2=0x0;var password=parseInt(pass,10);for(var c in nonce){c= nonce[c];if(c!= _0xba8b[0]){if(flag){num2= password;}flag= false;}switch(c){case _0xba8b[1]:num1= num2& 0xFFFFFF80;num1= num1>>> 7;num2= num2<< 25;num1= num1+ num2;break;case _0xba8b[2]:num1= num2& 0xFFFFFFF0;num1= num1>>> 4;num2= num2<< 28;num1= num1+ num2;break;case _0xba8b[3]:num1= num2& 0xFFFFFFF8;num1= num1>>> 3;num2= num2<< 29;num1= num1+ num2;break;case _0xba8b[4]:num1= num2<< 1;num2= num2>>> 31;num1= num1+ num2;break;case _0xba8b[5]:num1= num2<< 5;num2= num2>>> 27;num1= num1+ num2;break;case _0xba8b[6]:num1= num2<< 12;num2= num2>>> 20;num1= num1+ num2;break;case _0xba8b[7]:num1= num2& 0x0000FF00;num1= num1+ ((num2& 0x000000FF)<< 24);num1= num1+ ((num2& 0x00FF0000)>>> 16);num2= (num2& 0xFF000000)>>> 8;num1= num1+ num2;break;case _0xba8b[8]:num1= num2& 0x0000FFFF;num1= num1<< 16;num1= num1+ (num2>>> 24);num2= num2& 0x00FF0000;num2= num2>>> 8;num1= num1+ num2;break;case _0xba8b[9]:num1= ~num2;break;case _0xba8b[0]:num1= num2;break;}num2= num1;}return (num1>>> 0).toString(); } /** From e0a75b3c9cd9484e6fa47c4ff242fbf29e0e8aff Mon Sep 17 00:00:00 2001 From: simont77 <26008536+simont77@users.noreply.github.com> Date: Wed, 31 Jan 2018 13:33:36 +0100 Subject: [PATCH 31/96] get initialTime from fakegato --- index.js | 21 ++------------------- 1 file changed, 2 insertions(+), 19 deletions(-) diff --git a/index.js b/index.js index c4ed5d6..2ebcf98 100644 --- a/index.js +++ b/index.js @@ -1368,7 +1368,6 @@ class MHDryContact { this.lastOpening = 0; this.state = config.state || false; this.log.info(sprintf("LegrandMyHome::MHDryContact create object: %s", this.address)); - this.cacheFilename = path.join(this.config.parent.api.user.cachedAccessoryPath(),this.displayName+'.json'); } identify(callback) { @@ -1400,15 +1399,7 @@ class MHDryContact { if (this.firstGet) { this.firstGet = false; this.LoggingService.addEntry({time: moment().unix(), status: this.state}); - if (fs.existsSync(this.cacheFilename)) - { - this.offset = JSON.parse(fs.readFileSync(this.cacheFilename)); - } - else - { - this.offset = moment().unix(); - fs.writeFileSync(this.cacheFilename,JSON.stringify(this.offset)); - } + this.offset = this.LoggingService.getInitialTime(); } callback(null, this.state); }); @@ -1458,15 +1449,7 @@ class MHDryContact { if (this.firstGet) { this.firstGet = false; this.LoggingService.addEntry({time: moment().unix(), status: this.state}); - if (fs.existsSync(this.cacheFilename)) - { - this.offset = JSON.parse(fs.readFileSync(this.cacheFilename)); - } - else - { - this.offset = moment().unix(); - fs.writeFileSync(this.cacheFilename,JSON.stringify(this.offset)); - } + this.offset = this.LoggingService.getInitialTime(); } callback(null, this.state); }); From a264e2cae2d8a9fd9f3af8f2fef3bbad5d97c9ac Mon Sep 17 00:00:00 2001 From: simont77 <26008536+simont77@users.noreply.github.com> Date: Thu, 1 Feb 2018 17:10:42 +0100 Subject: [PATCH 32/96] moved average power calculation to fakegato --- index.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/index.js b/index.js index 2ebcf98..95a6a39 100644 --- a/index.js +++ b/index.js @@ -1257,19 +1257,19 @@ class MHPowerMeter { this.log.info(sprintf("LegrandMyHome::MHPowerMeter create object")); correctingInterval.setCorrectingInterval(function(){ this.totalenergy = this.totalenergy + this.value * this.refresh / 3600 / 1000; - this.intPower = this.intPower + this.value; - if (this.acquiredSamples Date: Wed, 7 Feb 2018 12:09:21 +0100 Subject: [PATCH 33/96] update pedencencies --- LICENSE | 2 ++ package.json | 7 ++----- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/LICENSE b/LICENSE index e5c0149..b69f467 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,8 @@ MIT License Copyright (c) 2016 angeloxx +Copyright (c) 2017 Simone Tisa + Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/package.json b/package.json index eabb300..6dd2878 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-myhome-tng", - "version": "0.1.5", + "version": "0.1.6", "description": "Legrand MyHome plugin for homebridge: https://github.com/nfarina/homebridge", "license": "MIT", "keywords": [ @@ -18,18 +18,15 @@ "url": "https://github.com/simont77/homebridge-myhome" }, "dependencies": { - "colorsys": "^1.0.9", "debug": "^2.4.5", "net": "^1.0.0", "promise": "^7.0.0", "sha1": "^1.1.1", "sha256": "^0.2.0", - "sprint-js": "^0.1.0", "sprintf-js": "^1.0.3", - "wait-until": "^0.0.2", "inherits": "^2.0.0", "moment": "^2.18.1", "correcting-interval":"^2.0.0", - "fakegato-history":"^0.3.8" + "fakegato-history":"^0.3.9" } } From d2034b686f306a53dd1319c2f4be7a957ba12386 Mon Sep 17 00:00:00 2001 From: simont77 <26008536+simont77@users.noreply.github.com> Date: Wed, 7 Feb 2018 14:15:55 +0100 Subject: [PATCH 34/96] update dependencies --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6dd2878..6c617ad 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,6 @@ "inherits": "^2.0.0", "moment": "^2.18.1", "correcting-interval":"^2.0.0", - "fakegato-history":"^0.3.9" + "fakegato-history":"^0.4.0" } } From a7c427afe334bad8c213756d23a7a2b297399d2d Mon Sep 17 00:00:00 2001 From: simont77 <26008536+simont77@users.noreply.github.com> Date: Wed, 14 Feb 2018 21:32:18 +0100 Subject: [PATCH 35/96] initial addition of MHIrrigation --- index.js | 118 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 117 insertions(+), 1 deletion(-) diff --git a/index.js b/index.js index 95a6a39..59817f5 100644 --- a/index.js +++ b/index.js @@ -187,6 +187,8 @@ class LegrandMyHome { if (accessory.accessory == 'MHPowerMeter') this.devices.push(new MHPowerMeter(this.log,accessory)); if (accessory.accessory == 'MHAlarm') this.devices.push(new MHAlarm(this.log,accessory)); if (accessory.accessory == 'MHControlledLoad') this.devices.push(new MHControlledLoad(this.log,accessory)); + if (accessory.accessory == 'MHIrrigation') this.devices.push(new MHIrrigation(this.log,accessory)); + }.bind(this)); this.log.info("LegrandMyHome for MyHome Gateway at " + config.ipaddress + ":" + config.port); this.controller.start(); @@ -231,6 +233,11 @@ class LegrandMyHome { accessory.power = _onoff; accessory.OutletService.getCharacteristic(Characteristic.On).getValue(null); } + if (accessory.address == _address && accessory.IrrigationService !== undefined) { + accessory.power = _onoff; + accessory.IrrigationService.getCharacteristic(Characteristic.Active).getValue(null); + accessory.IrrigationService.getCharacteristic(Characteristic.InUse).getValue(null); + } }.bind(this)); else if (a==0) @@ -274,7 +281,16 @@ class LegrandMyHome { accessory.contactSensorService.getCharacteristic(Characteristic.ContactSensorState).getValue(null); } }.bind(this)); - } + } + onRelayDuration(_address,_value) { + this.devices.forEach(function(accessory) { + if (accessory.address == _address && accessory.IrrigationService !== undefined) { + accessory.timer = _value; + accessory.IrrigationService.getCharacteristic(Characteristic.SetDuration).getValue(null); + } + }.bind(this)); + } + onDryContact(_address,_state) { this.devices.forEach(function(accessory) { @@ -1697,4 +1713,104 @@ class MHControlledLoad { return [service, this.controlledLoad]; } +} + +class MHIrrigation { + constructor(log, config) { + this.config = config || {}; + this.mh = config.parent.controller; + this.name = config.name; + this.address = config.address; + this.groups = config.groups || []; /* TODO */ + this.pul = config.pul || false; + this.displayName = config.name; + this.UUID = UUIDGen.generate(sprintf("irrigation-%s",config.address)); + this.log = log; + this.power = false; + this.askDuration = false; + this.timer = config.timer || 1; + this.log.info(sprintf("LegrandMyHome::MHIrrigation create object: %s", this.address)); + this.mh.addLightBusDevice(this.address); + + var address = this.address.split("/"); + this.bus = parseInt(address[0]); + this.ambient = parseInt(address[1]); + this.pl = parseInt(address[2]); + } + + getServices() { + var service = new Service.AccessoryInformation(); + service.setCharacteristic(Characteristic.Name, this.name) + .setCharacteristic(Characteristic.Manufacturer, "Simone Tisa") + .setCharacteristic(Characteristic.Model, "Irrigation") + .setCharacteristic(Characteristic.FirmwareRevision, version) + .setCharacteristic(Characteristic.SerialNumber, "Address " + this.address); + + + this.IrrigationService = new Service.Valve(this.name); + this.IrrigationService.setCharacteristic(Characteristic.ValveType,1); + this.IrrigationService.getCharacteristic(Characteristic.Active) + .on('set', (_value, callback) => { + //this.log.debug(sprintf("setPower %s = %s",this.address, level)); + this.power = _value; + + if (this.power) + { + var address = this.mh._slashesToAddress(this.address); + this.mh.send(sprintf("*#1*%s*#2*0*%d*0##",address,this.timer/60)); + } + else + { + this.mh.relayCommand(this.address,this.power); + clearInterval(this.timerHandle); + this.RemDuration = this.timer; + } + callback(null); + }) + .on('get', (callback) => { + this.log.debug(sprintf("getPower %s = %s",this.address, this.power)); + callback(null, this.power); + }); + this.IrrigationService.getCharacteristic(Characteristic.InUse) + .on('get', (callback) => { + if (this.power && this.askDuration) + { + var address = this.mh._slashesToAddress(this.address); + this.mh.send(sprintf("*#1*%s*2##",address)); + this.askDuration = false; + } + callback(null, this.power); + }); + this.IrrigationService.getCharacteristic(Characteristic.SetDuration) + .on('set', (time, callback) => { + this.timer = time; + callback(null); + }) + .on('get', (callback) => { + this.log.debug(sprintf("getPower %s = %s",this.address, this.power)); + if (this.power && this.timer !=0) + { + this.RemDuration = this.timer; + this.timerHandle = setInterval((function() { + this.IrrigationService.setCharacteristic(Characteristic.RemainingDuration,this.RemDuration); + this.RemDuration--; + if (this.RemDuration == 0) + clearInterval(this.timerHandle); + }.bind(this),1000); + } + callback(null, this.timer); + }); + this.IrrigationService.getCharacteristic(Characteristic.RemainingDuration) + .on('set', (time, callback) => { + this.RemainingDuration = time; + callback(null); + }) + .on('get', (callback) => { + this.log.debug(sprintf("getPower %s = %s",this.address, this.power)); + callback(null, this.remainingDuration); + }); + + + return [service, this.IrrigationService]; + } } \ No newline at end of file From c13999e52ac37de451e282ec239e996fda41d815 Mon Sep 17 00:00:00 2001 From: simont77 <26008536+simont77@users.noreply.github.com> Date: Wed, 14 Feb 2018 23:29:12 +0100 Subject: [PATCH 36/96] added control of remaining time, still to be fixed --- index.js | 28 +++++++++++++++++----------- lib/mhclient.js | 9 +++++++++ 2 files changed, 26 insertions(+), 11 deletions(-) diff --git a/index.js b/index.js index 59817f5..f40e679 100644 --- a/index.js +++ b/index.js @@ -207,6 +207,8 @@ class LegrandMyHome { this.controller.getRelayState(accessory.address); if (accessory.rainService !== undefined && accessory.pul == true) this.controller.getRelayState(accessory.address); + if (accessory.IrrigationService !== undefined && accessory.pul == true) + this.controller.getRelayState(accessory.address); if (accessory.alarmService !== undefined) this.controller.getAlarmState(); }.bind(this)); @@ -235,6 +237,7 @@ class LegrandMyHome { } if (accessory.address == _address && accessory.IrrigationService !== undefined) { accessory.power = _onoff; + accessory.askDuration = true; accessory.IrrigationService.getCharacteristic(Characteristic.Active).getValue(null); accessory.IrrigationService.getCharacteristic(Characteristic.InUse).getValue(null); } @@ -285,8 +288,9 @@ class LegrandMyHome { onRelayDuration(_address,_value) { this.devices.forEach(function(accessory) { if (accessory.address == _address && accessory.IrrigationService !== undefined) { - accessory.timer = _value; - accessory.IrrigationService.getCharacteristic(Characteristic.SetDuration).getValue(null); + if (accessory.askDuration) + accessory.timer = _value; + accessory.IrrigationService.getCharacteristic(Characteristic.SetDuration).getValue(null); } }.bind(this)); } @@ -1728,7 +1732,9 @@ class MHIrrigation { this.log = log; this.power = false; this.askDuration = false; + this.RemDuration = 1; this.timer = config.timer || 1; + this.timerHandle = 0; this.log.info(sprintf("LegrandMyHome::MHIrrigation create object: %s", this.address)); this.mh.addLightBusDevice(this.address); @@ -1751,19 +1757,20 @@ class MHIrrigation { this.IrrigationService.setCharacteristic(Characteristic.ValveType,1); this.IrrigationService.getCharacteristic(Characteristic.Active) .on('set', (_value, callback) => { - //this.log.debug(sprintf("setPower %s = %s",this.address, level)); + this.log.debug(sprintf("setIrrigation %s = %s",this.address, _value)); this.power = _value; if (this.power) { var address = this.mh._slashesToAddress(this.address); - this.mh.send(sprintf("*#1*%s*#2*0*%d*0##",address,this.timer/60)); + this.mh.send(sprintf("*#1*%s*#2*0*%d*%d##",address,this.timer/60, this.timer%60)); } else { this.mh.relayCommand(this.address,this.power); clearInterval(this.timerHandle); this.RemDuration = this.timer; + this.IrrigationService.setCharacteristic(Characteristic.RemainingDuration,this.RemDuration); } callback(null); }) @@ -1788,26 +1795,25 @@ class MHIrrigation { }) .on('get', (callback) => { this.log.debug(sprintf("getPower %s = %s",this.address, this.power)); - if (this.power && this.timer !=0) + if (this.power && this.timer !=0 && this.timerHandle==0) { this.RemDuration = this.timer; - this.timerHandle = setInterval((function() { - this.IrrigationService.setCharacteristic(Characteristic.RemainingDuration,this.RemDuration); + this.timerHandle = setInterval(function() { + this.IrrigationService.setCharacteristic(Characteristic.RemainingDuration,this.RemDuration); this.RemDuration--; if (this.RemDuration == 0) clearInterval(this.timerHandle); }.bind(this),1000); } - callback(null, this.timer); + callback(null, this.timer); }); this.IrrigationService.getCharacteristic(Characteristic.RemainingDuration) .on('set', (time, callback) => { - this.RemainingDuration = time; + this.RemDuration = time; callback(null); }) .on('get', (callback) => { - this.log.debug(sprintf("getPower %s = %s",this.address, this.power)); - callback(null, this.remainingDuration); + callback(null, this.RemDuration); }); diff --git a/lib/mhclient.js b/lib/mhclient.js index 1b82ae2..ec3ed7b 100755 --- a/lib/mhclient.js +++ b/lib/mhclient.js @@ -208,6 +208,15 @@ class MyHomeClient { } } + /* Relay time duration */ + // *#1*12*2*190*1*5##> + extract = frame.match(/^\*#1\*([0-9#]+)\*2\*(\d+)\*(\d+)\*(\d+)$/); + if (extract) { + let address = this._addressToSlashes(extract[1]); + if (this.parent != null && this.parent.onMonitor != null && typeof(this.parent.onRelayDuration) == 'function') + this.parent.onRelayDuration(address,parseInt(extract[2],10)*3600+parseInt(extract[3],10)*60+parseInt(extract[4],10)); + } + /* Light level - Advanced (VantageControls) way */ // *#1*12*1*190*1##> extract = frame.match(/^\*#1\*([0-9#]+)\*\d\*(\d+)\*\d+$/); From 4d94e3795378ae56757a1f69d3db3a96f0cfd5ac Mon Sep 17 00:00:00 2001 From: simont77 <26008536+simont77@users.noreply.github.com> Date: Thu, 15 Feb 2018 21:00:46 +0100 Subject: [PATCH 37/96] optimized remaining duration control --- index.js | 61 +++++++++++++++++++++++++++++++++----------------------- 1 file changed, 36 insertions(+), 25 deletions(-) diff --git a/index.js b/index.js index f40e679..3869a16 100644 --- a/index.js +++ b/index.js @@ -288,9 +288,20 @@ class LegrandMyHome { onRelayDuration(_address,_value) { this.devices.forEach(function(accessory) { if (accessory.address == _address && accessory.IrrigationService !== undefined) { - if (accessory.askDuration) - accessory.timer = _value; - accessory.IrrigationService.getCharacteristic(Characteristic.SetDuration).getValue(null); + //if (accessory.adjustDuration) + // accessory.timer = _value; + //accessory.IrrigationService.getCharacteristic(Characteristic.SetDuration).getValue(null); + if (accessory.power && accessory.timer !=0) + { + accessory.RemDuration = accessory.timer; + accessory.timerHandle = setInterval(function() { + accessory.IrrigationService.setCharacteristic(Characteristic.RemainingDuration,accessory.RemDuration); + accessory.RemDuration--; + if (accessory.RemDuration == 0) + clearInterval(accessory.timerHandle); + }.bind(this),1000); + } + } }.bind(this)); } @@ -1731,7 +1742,6 @@ class MHIrrigation { this.UUID = UUIDGen.generate(sprintf("irrigation-%s",config.address)); this.log = log; this.power = false; - this.askDuration = false; this.RemDuration = 1; this.timer = config.timer || 1; this.timerHandle = 0; @@ -1759,52 +1769,53 @@ class MHIrrigation { .on('set', (_value, callback) => { this.log.debug(sprintf("setIrrigation %s = %s",this.address, _value)); this.power = _value; - if (this.power) { var address = this.mh._slashesToAddress(this.address); - this.mh.send(sprintf("*#1*%s*#2*0*%d*%d##",address,this.timer/60, this.timer%60)); + this.mh.send(sprintf("*#1*%s*#2*0*%d*%d##",address,this.timer/60, this.timer%60)); } else { this.mh.relayCommand(this.address,this.power); - clearInterval(this.timerHandle); - this.RemDuration = this.timer; - this.IrrigationService.setCharacteristic(Characteristic.RemainingDuration,this.RemDuration); } + callback(null); }) .on('get', (callback) => { - this.log.debug(sprintf("getPower %s = %s",this.address, this.power)); + this.log.debug(sprintf("getIrrigation %s = %s",this.address, this.power)); callback(null, this.power); + /*}) + .on('change',() => { + if(!this.power) + { + clearInterval(this.timerHandle); + this.RemDuration = this.timer; + this.IrrigationService.setCharacteristic(Characteristic.RemainingDuration,this.RemDuration); + }*/ }); this.IrrigationService.getCharacteristic(Characteristic.InUse) .on('get', (callback) => { - if (this.power && this.askDuration) + callback(null, this.power); + }) + .on('change',() => { + if (this.power) // && this.askDuration) { var address = this.mh._slashesToAddress(this.address); this.mh.send(sprintf("*#1*%s*2##",address)); - this.askDuration = false; } - callback(null, this.power); + else + { + clearInterval(this.timerHandle); + this.RemDuration = this.timer; + this.IrrigationService.setCharacteristic(Characteristic.RemainingDuration,this.RemDuration); + } }); this.IrrigationService.getCharacteristic(Characteristic.SetDuration) .on('set', (time, callback) => { this.timer = time; callback(null); }) - .on('get', (callback) => { - this.log.debug(sprintf("getPower %s = %s",this.address, this.power)); - if (this.power && this.timer !=0 && this.timerHandle==0) - { - this.RemDuration = this.timer; - this.timerHandle = setInterval(function() { - this.IrrigationService.setCharacteristic(Characteristic.RemainingDuration,this.RemDuration); - this.RemDuration--; - if (this.RemDuration == 0) - clearInterval(this.timerHandle); - }.bind(this),1000); - } + .on('get', (callback) => { callback(null, this.timer); }); this.IrrigationService.getCharacteristic(Characteristic.RemainingDuration) From 39ada95b950c1214d7d7840f65862f9ba6c9876e Mon Sep 17 00:00:00 2001 From: simont77 <26008536+simont77@users.noreply.github.com> Date: Fri, 16 Feb 2018 08:24:19 +0100 Subject: [PATCH 38/96] removed unused dependencies --- index.js | 2 +- lib/mhclient.js | 2 +- package.json | 3 --- 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/index.js b/index.js index 3869a16..6e42c99 100644 --- a/index.js +++ b/index.js @@ -1,7 +1,7 @@ /*jshint esversion: 6,node: true,-W041: false */ var path = require("path"); var mh = require(path.join(__dirname,'/lib/mhclient')); -var sprintf = require("sprintf-js").sprintf, inherits = require("util").inherits, Promise = require('promise'); +var sprintf = require("sprintf-js").sprintf, inherits = require("util").inherits; var events = require('events'), util = require('util'), fs = require('fs'); var Accessory, Characteristic, Service, UUIDGen; var moment = require('moment'); diff --git a/lib/mhclient.js b/lib/mhclient.js index ec3ed7b..80c181b 100755 --- a/lib/mhclient.js +++ b/lib/mhclient.js @@ -3,7 +3,7 @@ const debug = require('debug')('myhomeclient'); const sprintf = require("sprintf-js").sprintf; const net = require('net'); const crypto = require('crypto'); -const sha256 = require('sha256'), sha1 = require('sha1'); +const sha256 = require('sha256'); const moment = require('moment'); diff --git a/package.json b/package.json index 6c617ad..579d4a7 100644 --- a/package.json +++ b/package.json @@ -20,11 +20,8 @@ "dependencies": { "debug": "^2.4.5", "net": "^1.0.0", - "promise": "^7.0.0", - "sha1": "^1.1.1", "sha256": "^0.2.0", "sprintf-js": "^1.0.3", - "inherits": "^2.0.0", "moment": "^2.18.1", "correcting-interval":"^2.0.0", "fakegato-history":"^0.4.0" From 1266f0ddfa8f762489aa6208a48da4a7df1c48fa Mon Sep 17 00:00:00 2001 From: simont77 <26008536+simont77@users.noreply.github.com> Date: Fri, 16 Feb 2018 20:18:11 +0100 Subject: [PATCH 39/96] update readme and sample_config.json --- README.md | 89 +++++++++------------------------------------- sample-config.json | 65 --------------------------------- sample_config.json | 75 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 92 insertions(+), 137 deletions(-) delete mode 100644 sample-config.json create mode 100755 sample_config.json diff --git a/README.md b/README.md index d479a95..0ca0750 100644 --- a/README.md +++ b/README.md @@ -6,14 +6,15 @@ Legrand MyHome (http://www.homesystems-legrandgroup.com/BtHomeSystems/home.actio - thermoregulation - curtains, doors - security systems +- contact and motion sensors With this plugin, the support of a IP gateway installed in your plant and a configuration of all installed systems (MyHome does not support the autodiscovery of the system) you can control it. You need to disable the OpenWebNet password-based authentication from the IP of the device that runs homebridge (ie. Raspberry) or set the auhentication to HMAC; HMAC authentication is supported by all recent IP gateways or older one with updated firmware (eg. F454 with v2 firmware). -# Installation (TBD) -Install plugin with npm install -g homebridge-myhome +# Installation +Install plugin with npm install -g simont77/homebridge-myhome Add platform within config.json of you homebridge instance: { @@ -22,6 +23,7 @@ Add platform within config.json of you homebridge instance: "ipaddress": "192.168.1.1", "password": "12345", "discovery": false, + "setclock": true, "devices": [ /*Static list of devices*/ ] @@ -39,16 +41,6 @@ Add platform within config.json of you homebridge instance: Restart homebridge Enjoy! -# Installation - -Run as root: - - npm -g install homebridge-myhome-tng - -Create your config.json file starting from the template (sample-config.json) and then: - - homebridge -U . - Sample log is: [1/14/2017, 12:11:29 AM] Plugin /usr/lib/nodejs does not have a package name that begins with 'homebridge-'. @@ -88,52 +80,7 @@ Sample log is: ## Configuration -Only the platforms section of the config.json file should be edited, the pair code and the port in bridge section can be ignored in most of the cases. A little sample: - - { - "platforms": [{ - "platform": "LegrandMyHome", - "ipaddress": "192.168.157.207", - "port": 20000, - "ownpassword": "12345", - "discovery": false, - "devices": [{ - "accessory": "MHRelay", - "name": "Bathroom Light", - "address": "0/1/5" - },{ - "accessory": "MHRelay", - "name": "Night hallway Light", - "address": "0/1/1" - },{ - "accessory": "MHRelay", - "name": "Office", - "address": "0/1/4" - },{ - "accessory": "MHDimmer", - "name": "Master bedroom Central", - "address": "0/1/2" - },{ - "accessory": "MHThermostat", - "name": "Living Room Thermostat", - "address": "21" - },{ - "accessory": "MHThermostatExternal", - "name": "External Thermo Sensor", - "address": "1" - }] - }], - "bridge": { - "username": "CC:22:3D:E3:CE:31", - "name": "MyHome HomeBridge Adapter", - "pin": "342-52-220", - "port": 51827 - }, - "description": "My MyHome Home System", - "accessories": [ - ] - } - +Only the platforms section of the config.json file should be edited, the pair code and the port in bridge section can be ignored in most of the cases. The first part of the config file contains details about the MyHome Gateway used to interface the IP network with the plant: "platforms": [{ @@ -142,13 +89,14 @@ The first part of the config file contains details about the MyHome Gateway used "port": 20000, "ownpassword": "12345", "discovery": false, + "setclock": true, "devices": [{ You need to change: - ipaddress: put the IP address or name of the MyHome Gateway (eg. F454 or MH201, I'm not so updated about all gateways that BTicino-Legrand releases after 2015); the IP should be static but in the future I can implement a UPNP dicovery because all gateways supports that method - port: should be 20000 and keep this value - ownpassword: the OpenWebNet password, default is 12345 but everyone will suggest to you to change it with another password (4 to 9 digits), but you will keep the default one, I know... -- discovery: boolean value, not supported but in the future allows the gateway to discover the plant and detect most of devices +- setclock: set to true if you want your homebridge server to set the time of your gateway every hour - devices: list of installed devices The devices section contains the list of devices that will be managed. All devices contains three standard properties: @@ -159,8 +107,7 @@ The devices section contains the list of devices that will be managed. All devic ## Supported devices -* MHRelay: Standard (Lighting) Relay (eg. F411), address is B/A/PL (eg. 0/1/10) - * this device supports the definition of a custom frame for on and off command, so you can specify frame\_on and/or frame\_off: +* MHRelay: Standard (Lighting) Relay (eg. F411), address is B/A/PL (eg. 0/1/10). This device supports the definition of a custom frame for on and off command, so you can specify frame\_on and/or frame\_off: { "accessory": "MHRelay", @@ -180,12 +127,17 @@ The devices section contains the list of devices that will be managed. All devic * MHBlind: Standard Automation Relay (eg. F411, I need to check the F401), address is B/A/PL (eg. 0/1/10) * this device defines another property called "time" that defines the configured "stop time" in seconds; using this property the driver can evaluate the current position of the blind * MHBlindAdvanced: Advanced version of standard Blind (eg. F401 that manages internally the current position), address is B/A/PL (eg. 0/1/10) -* MHContactSensor: Dry Contact sensor (eg. 3477 or some burgalarm sensors), address range is 1-201 -* MHPowerMeter: (WILL BE SUPPORTED) -* MHAlarm: (WILL BE SUPPORTED) +* MHContactSensor: Dry Contact sensor (eg. 3477 or some burgalarm sensors), address range is 1-201. Supported types are "motion", "contact" +* MHPowerMeter: Only supported with F421 Load Control Central, use "refresh" to set the update interval +* MHAlarm: tested on central 3486. Zones for Away, Night and At Home activation are currently hard coded in plugin code. Alarm activation/deactivation from Homekit is not implemented for security reasons, so monitor of the current status is supported +* MHTimedRelay: to issue temporized command to relays. Default duration set in "duration" +* MHControlledLoad: to control status of old generation Load Control outlets +* MHAux: to deliver AUX events to Homekit. Supported type are "leak", "gas" and contact". + +See sample-config.json for the additional parameters of each accessory. ## Tested devices -- F454v1 and MH201 as IP Gateway +- F454v1, MH200N and MH201 as IP Gateway - F411/2 as MHRelay, MHOutlet and MHCurtain - F401 as MHBlindAdvanced - F416U1 as MHDimmer @@ -196,13 +148,6 @@ The devices section contains the list of devices that will be managed. All devic - Groups are not managed -# TODOS - -- Reconnection and infinite retry -- Semi-auto discovery and/or read a plant configuration from MyHomeSuite configuration file -- Re-order the code -- IP Gateway discovery -- Group and General Command support # Disclaimer diff --git a/sample-config.json b/sample-config.json deleted file mode 100644 index fcb3673..0000000 --- a/sample-config.json +++ /dev/null @@ -1,65 +0,0 @@ -{ - "platforms": [{ - "platform": "LegrandMyHome", - "ipaddress": "192.168.157.207", - "port": 20000, - "ownpassword": "12345", - "discovery": false, - "devices": [{ - "accessory": "MHRelay", - "name": "Bathroom Light", - "address": "0/1/5" - },{ - "accessory": "MHRelay", - "name": "Night hallway Light", - "address": "0/1/1" - },{ - "accessory": "MHRelay", - "name": "Office", - "address": "0/1/4" - },{ - "accessory": "MHDimmer", - "name": "Master bedroom Central", - "address": "0/1/2" - },{ - "accessory": "MHOutlet", - "name": "Master bedroom Thermal Blanket", - "address": "0/2/3" - },{ - "accessory": "MHContactSensor", - "name": "Bedroom presence sensor", - "address": "21" - },{ - "accessory": "MHThermostat", - "name": "Living Room Thermostat", - "address": "21" - },{ - "accessory": "MHExternalThermometer", - "name": "External Thermo Sensor", - "address": "5" - },{ - "accessory": "MHBlind", - "name": "Sample Curtain", - "address": "0/6/3", - "time": 10 - },{ - "accessory": "MHBlindAdvanced", - "name": "Sample Advanced Curtain", - "address": "0/6/4" - },{ - "accessory": "MHPowerMeter", - "name": "Sample Meter", - "address": "0/6/3", - "time": 10 - }] - }], - "bridge": { - "username": "CC:22:3D:E3:CE:31", - "name": "MyHome HomeBridge Adapter", - "pin": "023-42-522", - "port": 51827 - }, - "description": "My MyHome Home System", - "accessories": [ - ] -} \ No newline at end of file diff --git a/sample_config.json b/sample_config.json new file mode 100755 index 0000000..a123317 --- /dev/null +++ b/sample_config.json @@ -0,0 +1,75 @@ +{ + "platforms": [{ + "platform": "LegrandMyHome", + "ipaddress": "192.168.1.2", + "port": 20000, + "ownpassword": "12345", + "discovery": false, + "setclock": true, + "devices": [{ + "accessory": "MHRelay", + "name": "Sample light", + "address": "0/1/2" + },{ + "accessory": "MHDimmer", + "name": "Sample dimmer", + "address": "0/1/1" + },{ + "accessory": "MHBlind", + "name": "Sample blind", + "address": "0/3/1", + "time": 28 + },{ + "accessory": "MHBlindAdvanced", + "name": "Sample Advanced Curtain", + "address": "0/3/2" + },{ + "accessory": "MHOutlet", + "name": "Sample outlet", + "address": "0/2/1", + "pul":true + },{ + "accessory": "MHTimedRelay", + "name": "Sample timed relay", + "address": "0/4/1", + "pul":true, + "timer":300 + },{ + "accessory": "MHPowerMeter", + "name": "Sample powermeter", + "refresh": 10 + },{ + "accessory": "MHAlarm", + "name": "Sample alarm" + },{ + "accessory": "MHDryContact", + "name": "Sample contact", + "address": "10", + "type": "Contact" + },{ + "accessory": "MHAux", + "name": "Sample aux", + "address": "3", + "type": "Leak" + },{ + "accessory": "MHControlledLoad", + "name": "Sample controlled load", + "address": "4" + },{ + "accessory": "MHThermostat", + "name": "Sample Thermostat", + "address": "21" + },{ + "accessory": "MHExternalThermometer", + "name": "Sample Thermo Sensor", + "address": "5" + }] + }], + "bridge": { + "username": "11:22:33:44:55:66", + "name": "MyHome HomeBridge Adapter", + "pin": "123-45-678", + "port": 51827 + }, + "description": "My MyHome Home System" +} From dc38f9a576fe5e37cd2662a9036af194f2c17eca Mon Sep 17 00:00:00 2001 From: simont77 <26008536+simont77@users.noreply.github.com> Date: Fri, 16 Feb 2018 20:26:04 +0100 Subject: [PATCH 40/96] Update README.md --- README.md | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 0ca0750..d77c292 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ authentication from the IP of the device that runs homebridge (ie. Raspberry) or HMAC authentication is supported by all recent IP gateways or older one with updated firmware (eg. F454 with v2 firmware). # Installation -Install plugin with npm install -g simont77/homebridge-myhome +Install plugin with `npm install -g simont77/homebridge-myhome` Add platform within config.json of you homebridge instance: { @@ -38,8 +38,7 @@ Add platform within config.json of you homebridge instance: "accessories": [] } -Restart homebridge -Enjoy! +Restart homebridge. Sample log is: @@ -93,7 +92,7 @@ The first part of the config file contains details about the MyHome Gateway used "devices": [{ You need to change: -- ipaddress: put the IP address or name of the MyHome Gateway (eg. F454 or MH201, I'm not so updated about all gateways that BTicino-Legrand releases after 2015); the IP should be static but in the future I can implement a UPNP dicovery because all gateways supports that method +- ipaddress: put the IP address or name of the MyHome Gateway (eg. F454 or MH201) - port: should be 20000 and keep this value - ownpassword: the OpenWebNet password, default is 12345 but everyone will suggest to you to change it with another password (4 to 9 digits), but you will keep the default one, I know... - setclock: set to true if you want your homebridge server to set the time of your gateway every hour @@ -127,9 +126,9 @@ The devices section contains the list of devices that will be managed. All devic * MHBlind: Standard Automation Relay (eg. F411, I need to check the F401), address is B/A/PL (eg. 0/1/10) * this device defines another property called "time" that defines the configured "stop time" in seconds; using this property the driver can evaluate the current position of the blind * MHBlindAdvanced: Advanced version of standard Blind (eg. F401 that manages internally the current position), address is B/A/PL (eg. 0/1/10) -* MHContactSensor: Dry Contact sensor (eg. 3477 or some burgalarm sensors), address range is 1-201. Supported types are "motion", "contact" +* MHContactSensor: Dry Contact sensor (eg. 3477 or some burgalarm sensors), address range is 1-201. Supported types are "motion" and "contact" * MHPowerMeter: Only supported with F421 Load Control Central, use "refresh" to set the update interval -* MHAlarm: tested on central 3486. Zones for Away, Night and At Home activation are currently hard coded in plugin code. Alarm activation/deactivation from Homekit is not implemented for security reasons, so monitor of the current status is supported +* MHAlarm: tested on central 3486. Zones for Away, Night and At Home activation are currently hard coded in plugin code. Alarm activation/deactivation from Homekit is not implemented for security reasons, so only monitor of the current status is supported * MHTimedRelay: to issue temporized command to relays. Default duration set in "duration" * MHControlledLoad: to control status of old generation Load Control outlets * MHAux: to deliver AUX events to Homekit. Supported type are "leak", "gas" and contact". @@ -152,4 +151,4 @@ See sample-config.json for the additional parameters of each accessory. # Disclaimer I'm furnishing this software "as is". I do not provide any warranty of the item whatsoever, whether express, implied, or statutory, including, but not limited to, any warranty of merchantability or fitness for a particular purpose or any warranty that the contents of the item will be error-free. -The development of this module is not supported by Legrand, BTicino or Apple. These vendors and me are not responsible for direct, indirect, incidental or consequential damages resulting from any defect, error or failure to perform. \ No newline at end of file +The development of this module is not supported by Legrand, BTicino or Apple. These vendors and me are not responsible for direct, indirect, incidental or consequential damages resulting from any defect, error or failure to perform. From 47957f24a8e6b327d427fe040025044e00a1732f Mon Sep 17 00:00:00 2001 From: simont77 <26008536+simont77@users.noreply.github.com> Date: Fri, 16 Feb 2018 20:33:56 +0100 Subject: [PATCH 41/96] Update README.md --- README.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index d77c292..cfd426f 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # MyHomePlugin -Legrand (BTicino) MyHome plugin for homebridge: https://github.com/nfarina/homebridge +Legrand (BTicino) MyHome plugin for homebridge: https://github.com/nfarina/homebridge This is a fork of https://github.com/angeloxx/homebridge-myhome, with added accessories and support for Elgato Eve history feature for contact, motion sensor and powermeter. Legrand MyHome (http://www.homesystems-legrandgroup.com/BtHomeSystems/home.action) is an Home Automation solution that can manage: - lighting (standard on/off/dimmed lights) @@ -22,7 +22,6 @@ Add platform within config.json of you homebridge instance: "platform": "MyHome Gateway", "ipaddress": "192.168.1.1", "password": "12345", - "discovery": false, "setclock": true, "devices": [ /*Static list of devices*/ @@ -87,7 +86,6 @@ The first part of the config file contains details about the MyHome Gateway used "ipaddress": "192.168.157.207", "port": 20000, "ownpassword": "12345", - "discovery": false, "setclock": true, "devices": [{ @@ -126,12 +124,13 @@ The devices section contains the list of devices that will be managed. All devic * MHBlind: Standard Automation Relay (eg. F411, I need to check the F401), address is B/A/PL (eg. 0/1/10) * this device defines another property called "time" that defines the configured "stop time" in seconds; using this property the driver can evaluate the current position of the blind * MHBlindAdvanced: Advanced version of standard Blind (eg. F401 that manages internally the current position), address is B/A/PL (eg. 0/1/10) -* MHContactSensor: Dry Contact sensor (eg. 3477 or some burgalarm sensors), address range is 1-201. Supported types are "motion" and "contact" -* MHPowerMeter: Only supported with F421 Load Control Central, use "refresh" to set the update interval +* MHContactSensor: Dry Contact sensor (eg. 3477 or some burgalarm sensors), address range is 1-201. Supported types are "motion" and "contact". Elgato Eve history feature is supported. +* MHPowerMeter: Only supported with F421 Load Control Central, use "refresh" to set the update interval. Elgato Eve history feature is supported. * MHAlarm: tested on central 3486. Zones for Away, Night and At Home activation are currently hard coded in plugin code. Alarm activation/deactivation from Homekit is not implemented for security reasons, so only monitor of the current status is supported * MHTimedRelay: to issue temporized command to relays. Default duration set in "duration" * MHControlledLoad: to control status of old generation Load Control outlets * MHAux: to deliver AUX events to Homekit. Supported type are "leak", "gas" and contact". +* MHIrrigation: modified MHTimedRelay using the new Homekit irrigation service See sample-config.json for the additional parameters of each accessory. From 4547d7d424baf83ec3a6037cabba9b0b80af3b1a Mon Sep 17 00:00:00 2001 From: simont77 <26008536+simont77@users.noreply.github.com> Date: Fri, 16 Feb 2018 20:39:34 +0100 Subject: [PATCH 42/96] update sample_config.json --- sample_config.json | 1 - 1 file changed, 1 deletion(-) diff --git a/sample_config.json b/sample_config.json index a123317..69e6881 100755 --- a/sample_config.json +++ b/sample_config.json @@ -4,7 +4,6 @@ "ipaddress": "192.168.1.2", "port": 20000, "ownpassword": "12345", - "discovery": false, "setclock": true, "devices": [{ "accessory": "MHRelay", From 87ffdb9da944022c2f9264eaf7d8705d39e39848 Mon Sep 17 00:00:00 2001 From: simont77 <26008536+simont77@users.noreply.github.com> Date: Sun, 18 Feb 2018 14:56:58 +0100 Subject: [PATCH 43/96] fix and cleanup --- index.js | 31 +++++++------------------------ lib/mhclient.js | 16 +++++++++++----- 2 files changed, 18 insertions(+), 29 deletions(-) diff --git a/index.js b/index.js index 6e42c99..c04c78f 100644 --- a/index.js +++ b/index.js @@ -178,11 +178,9 @@ class LegrandMyHome { if (accessory.accessory == 'MHRain') this.devices.push(new MHRain(this.log,accessory)); if (accessory.accessory == 'MHDimmer') this.devices.push(new MHDimmer(this.log,accessory)); if (accessory.accessory == 'MHThermostat') this.devices.push(new MHThermostat(this.log,accessory)); - if (accessory.accessory == 'MHExternalThermometer') this.devices.push(new MHThermometer(this.log,accessory)); - + if (accessory.accessory == 'MHExternalThermometer') this.devices.push(new MHThermometer(this.log,accessory)); if (accessory.accessory == 'MHDryContact') this.devices.push(new MHDryContact(this.log,accessory)); if (accessory.accessory == 'MHAux') this.devices.push(new MHAux(this.log,accessory)); - /* if (accessory.accessory == 'MHButton') this.devices.push(new MHButton(this.log,accessory)) */ if (accessory.accessory == 'MHPowerMeter') this.devices.push(new MHPowerMeter(this.log,accessory)); if (accessory.accessory == 'MHAlarm') this.devices.push(new MHAlarm(this.log,accessory)); @@ -291,9 +289,9 @@ class LegrandMyHome { //if (accessory.adjustDuration) // accessory.timer = _value; //accessory.IrrigationService.getCharacteristic(Characteristic.SetDuration).getValue(null); - if (accessory.power && accessory.timer !=0) + if (accessory.power) { - accessory.RemDuration = accessory.timer; + accessory.RemDuration = _value; accessory.timerHandle = setInterval(function() { accessory.IrrigationService.setCharacteristic(Characteristic.RemainingDuration,accessory.RemDuration); accessory.RemDuration--; @@ -850,8 +848,7 @@ class MHTimedRelay { /* Custom frame support */ if (this.power && this.timer !=0) { - var address = this.mh._slashesToAddress(this.address); - this.mh.send(sprintf("*#1*%s*#2*0*%d*0##",address,this.timer/60)); + this.mh.relayTimedOn(this.address,this.timer/3600,this.timer/60,this.timer); } else { @@ -1747,7 +1744,6 @@ class MHIrrigation { this.timerHandle = 0; this.log.info(sprintf("LegrandMyHome::MHIrrigation create object: %s", this.address)); this.mh.addLightBusDevice(this.address); - var address = this.address.split("/"); this.bus = parseInt(address[0]); this.ambient = parseInt(address[1]); @@ -1762,7 +1758,6 @@ class MHIrrigation { .setCharacteristic(Characteristic.FirmwareRevision, version) .setCharacteristic(Characteristic.SerialNumber, "Address " + this.address); - this.IrrigationService = new Service.Valve(this.name); this.IrrigationService.setCharacteristic(Characteristic.ValveType,1); this.IrrigationService.getCharacteristic(Characteristic.Active) @@ -1771,8 +1766,7 @@ class MHIrrigation { this.power = _value; if (this.power) { - var address = this.mh._slashesToAddress(this.address); - this.mh.send(sprintf("*#1*%s*#2*0*%d*%d##",address,this.timer/60, this.timer%60)); + this.mh.relayTimedOn(this.address,this.timer/3600,this.timer/60,this.timer); } else { @@ -1784,24 +1778,15 @@ class MHIrrigation { .on('get', (callback) => { this.log.debug(sprintf("getIrrigation %s = %s",this.address, this.power)); callback(null, this.power); - /*}) - .on('change',() => { - if(!this.power) - { - clearInterval(this.timerHandle); - this.RemDuration = this.timer; - this.IrrigationService.setCharacteristic(Characteristic.RemainingDuration,this.RemDuration); - }*/ }); this.IrrigationService.getCharacteristic(Characteristic.InUse) .on('get', (callback) => { callback(null, this.power); }) .on('change',() => { - if (this.power) // && this.askDuration) + if (this.power) { - var address = this.mh._slashesToAddress(this.address); - this.mh.send(sprintf("*#1*%s*2##",address)); + this.mh.getRelayDuration(this.address); } else { @@ -1826,8 +1811,6 @@ class MHIrrigation { .on('get', (callback) => { callback(null, this.RemDuration); }); - - return [service, this.IrrigationService]; } } \ No newline at end of file diff --git a/lib/mhclient.js b/lib/mhclient.js index 80c181b..4e920d3 100755 --- a/lib/mhclient.js +++ b/lib/mhclient.js @@ -108,6 +108,12 @@ class MyHomeClient { this.command.send(sprintf("*1*%d*%s##",(_on)?1:0,address)); } + relayTimedOn(_address,hh,mm,ss) { + var address = this._slashesToAddress(_address); + if (address == "") return; + this.command.send(sprintf("*#1*%s*#2*%d*%d*%d##", address, hh, mm, ss)); + } + simpleBlindCommand(_address,_stopUpDown) { var address = this._slashesToAddress(_address); if (address == "") return; @@ -117,8 +123,6 @@ class MyHomeClient { this.command.send(sprintf("*2*%d*%s##",0,address)); } this.command.send(sprintf("*2*%d*%s##",parseInt(_stopUpDown),address)); - - } advancedBlindCommand(_address,_shutterLevel) { @@ -148,14 +152,12 @@ class MyHomeClient { { if (_address == "") return; if (_forced == 1) - this.command.send(sprintf("*3*2*#%d##",_address)); - + this.command.send(sprintf("*3*2*#%d##",_address)); } setSetPoint(_address,_temperature) { // Standard thermostat *4*40*%02d##*#4*#%02d*#14*%04d*3 this._bufferCommand("THERMO",_address,sprintf("*4*40*%02d##*#4*#%02d*#14*%04d*3##*#4*%02d*14##",_address,_address,_temperature * 10,_address),500); - // 4 Zones *#4*#0#%02d*#14*%04d*3 } @@ -429,6 +431,10 @@ class MyHomeClient { this.command.send(sprintf("*#1*%s##",this._slashesToAddress(_address))); } + getRelayDuration(_address) { + this.command.send(sprintf("*#1*%s*2##",this._slashesToAddress(_address))); + } + getAdvancedBlindState(_address) { this.command.send(sprintf("*#2*%s*10##",this._slashesToAddress(_address))); } From b437eadfab1ee9c8744cb732656adb0e6bd1cdae Mon Sep 17 00:00:00 2001 From: simont77 <26008536+simont77@users.noreply.github.com> Date: Thu, 15 Mar 2018 15:52:31 +0100 Subject: [PATCH 44/96] fix for lastOpening/lastActivation --- index.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/index.js b/index.js index 95a6a39..5265c2e 100644 --- a/index.js +++ b/index.js @@ -1399,7 +1399,6 @@ class MHDryContact { if (this.firstGet) { this.firstGet = false; this.LoggingService.addEntry({time: moment().unix(), status: this.state}); - this.offset = this.LoggingService.getInitialTime(); } callback(null, this.state); }); @@ -1407,7 +1406,7 @@ class MHDryContact { .on('change', () => { this.log.debug(sprintf("changeContactSensorState %s = %s",this.address, this.state)); this.LoggingService.addEntry({time: moment().unix(), status: this.state}); - this.lastOpening = moment().unix()-this.offset; + this.lastOpening = moment().unix()-this.LoggingService.getInitialTime(); if (this.state) this.numberOpened++; }); @@ -1449,7 +1448,6 @@ class MHDryContact { if (this.firstGet) { this.firstGet = false; this.LoggingService.addEntry({time: moment().unix(), status: this.state}); - this.offset = this.LoggingService.getInitialTime(); } callback(null, this.state); }); @@ -1457,7 +1455,7 @@ class MHDryContact { .on('change', () => { this.log.debug(sprintf("changeMotionSensorState %s = %s",this.address, this.state)); this.LoggingService.addEntry({time: moment().unix(), status: this.state}); - this.lastOpening = moment().unix()-this.offset; + this.lastOpening = moment().unix()-this.LoggingService.getInitialTime(); }); this.dryContactService.getCharacteristic(LegrandMyHome.Duration) .on('set', (value, callback) => { From 1f7500dc66831416d4500a5d42ce3aa5c13351f7 Mon Sep 17 00:00:00 2001 From: simont77 <26008536+simont77@users.noreply.github.com> Date: Fri, 16 Mar 2018 18:30:26 +0100 Subject: [PATCH 45/96] Update package.json --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6c617ad..a1cac27 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-myhome-tng", - "version": "0.1.6", + "version": "0.1.7", "description": "Legrand MyHome plugin for homebridge: https://github.com/nfarina/homebridge", "license": "MIT", "keywords": [ From bc81c939a561e576c7ca27f2755880ac6ec01466 Mon Sep 17 00:00:00 2001 From: simont77 <26008536+simont77@users.noreply.github.com> Date: Fri, 13 Apr 2018 17:01:26 +0200 Subject: [PATCH 46/96] - added optional storage parameter. If "fs" will persist history on filesystem, otherwise on googledrive - added fake history to irrigation to enable proper icon in Eve --- index.js | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/index.js b/index.js index 8378f18..31460b4 100644 --- a/index.js +++ b/index.js @@ -1334,8 +1334,10 @@ class MHPowerMeter { callback(null); }); - //this.powerLoggingService = new LegrandMyHome.FakeGatoHistoryService("energy", this,{storage: 'fs', path: this.config.parent.api.user.cachedAccessoryPath()}); - this.powerLoggingService = new LegrandMyHome.FakeGatoHistoryService("energy", this,{storage: 'googleDrive', path: 'homebridge'}); + if (config.storage == 'fs') + this.powerLoggingService = new LegrandMyHome.FakeGatoHistoryService("energy", this,{storage: 'fs'}); + else + this.powerLoggingService = new LegrandMyHome.FakeGatoHistoryService("energy", this,{storage: 'googleDrive', path: 'homebridge'}); return [service, this.powerMeterService, this.powerLoggingService]; } @@ -1414,8 +1416,10 @@ class MHDryContact { switch (this.type) { case 'Contact': this.dryContactService = new Service.ContactSensor(this.name); - //this.LoggingService = new LegrandMyHome.FakeGatoHistoryService("door", this,{storage: 'fs', path: this.config.parent.api.user.cachedAccessoryPath()}); - this.LoggingService = new LegrandMyHome.FakeGatoHistoryService("door", this,{storage: 'googleDrive', path: 'homebridge'}); + if (config.storage == 'fs') + this.LoggingService = new LegrandMyHome.FakeGatoHistoryService("door", this,{storage: 'fs'}); + else + this.LoggingService = new LegrandMyHome.FakeGatoHistoryService("door", this,{storage: 'googleDrive', path: 'homebridge'}); this.dryContactService.addCharacteristic(LegrandMyHome.LastActivation); this.dryContactService.addCharacteristic(LegrandMyHome.TimesOpened); this.dryContactService.addCharacteristic(LegrandMyHome.ResetTotal); @@ -1464,8 +1468,10 @@ class MHDryContact { return [service, this.dryContactService]; case 'Motion': this.dryContactService = new Service.MotionSensor(this.name); - //this.LoggingService = new LegrandMyHome.FakeGatoHistoryService("motion", this,{storage: 'fs', path: this.config.parent.api.user.cachedAccessoryPath()}); - this.LoggingService = new LegrandMyHome.FakeGatoHistoryService("motion", this,{storage: 'googleDrive', path: 'homebridge'}); + if (config.storage == 'fs') + this.LoggingService = new LegrandMyHome.FakeGatoHistoryService("motion", this,{storage: 'fs'}); + else + this.LoggingService = new LegrandMyHome.FakeGatoHistoryService("motion", this,{storage: 'googleDrive', path: 'homebridge'}); this.dryContactService.addCharacteristic(LegrandMyHome.Sensitivity); this.dryContactService.addCharacteristic(LegrandMyHome.Duration); this.dryContactService.addCharacteristic(LegrandMyHome.LastActivation); @@ -1757,6 +1763,11 @@ class MHIrrigation { .setCharacteristic(Characteristic.SerialNumber, "Address " + this.address); this.IrrigationService = new Service.Valve(this.name); + + // just to make the irrigation icon show in Eve, real history signature needed + this.LoggingService = new LegrandMyHome.FakeGatoHistoryService("motion", this, {size: 10, disableTimer: true}); + + this.IrrigationService.setCharacteristic(Characteristic.ValveType,1); this.IrrigationService.getCharacteristic(Characteristic.Active) .on('set', (_value, callback) => { @@ -1809,6 +1820,6 @@ class MHIrrigation { .on('get', (callback) => { callback(null, this.RemDuration); }); - return [service, this.IrrigationService]; + return [service, this.IrrigationService, this.LoggingService]; } } \ No newline at end of file From b990c27a6dc388e9a244fbc0a1ecd8f3d1b9accf Mon Sep 17 00:00:00 2001 From: simont77 <26008536+simont77@users.noreply.github.com> Date: Sat, 14 Apr 2018 12:46:13 +0200 Subject: [PATCH 47/96] removed useless timer, set duration of startup, shutdown homekit timer on power off --- index.js | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/index.js b/index.js index 31460b4..f00ad8d 100644 --- a/index.js +++ b/index.js @@ -235,7 +235,7 @@ class LegrandMyHome { } if (accessory.address == _address && accessory.IrrigationService !== undefined) { accessory.power = _onoff; - accessory.askDuration = true; + //accessory.askDuration = true; accessory.IrrigationService.getCharacteristic(Characteristic.Active).getValue(null); accessory.IrrigationService.getCharacteristic(Characteristic.InUse).getValue(null); } @@ -286,18 +286,10 @@ class LegrandMyHome { onRelayDuration(_address,_value) { this.devices.forEach(function(accessory) { if (accessory.address == _address && accessory.IrrigationService !== undefined) { - //if (accessory.adjustDuration) - // accessory.timer = _value; - //accessory.IrrigationService.getCharacteristic(Characteristic.SetDuration).getValue(null); if (accessory.power) { accessory.RemDuration = _value; - accessory.timerHandle = setInterval(function() { accessory.IrrigationService.setCharacteristic(Characteristic.RemainingDuration,accessory.RemDuration); - accessory.RemDuration--; - if (accessory.RemDuration == 0) - clearInterval(accessory.timerHandle); - }.bind(this),1000); } } @@ -1769,6 +1761,7 @@ class MHIrrigation { this.IrrigationService.setCharacteristic(Characteristic.ValveType,1); + this.IrrigationService.setCharacteristic(Characteristic.SetDuration,this.timer); this.IrrigationService.getCharacteristic(Characteristic.Active) .on('set', (_value, callback) => { this.log.debug(sprintf("setIrrigation %s = %s",this.address, _value)); @@ -1799,9 +1792,8 @@ class MHIrrigation { } else { - clearInterval(this.timerHandle); - this.RemDuration = this.timer; - this.IrrigationService.setCharacteristic(Characteristic.RemainingDuration,this.RemDuration); + this.RemDuration = 0; + this.IrrigationService.setCharacteristic(Characteristic.RemainingDuration,this.RemDuration); } }); this.IrrigationService.getCharacteristic(Characteristic.SetDuration) From 99063122e12d9e063c3389c58f68eed4b8f62f67 Mon Sep 17 00:00:00 2001 From: simont77 <26008536+simont77@users.noreply.github.com> Date: Sun, 15 Apr 2018 15:01:08 +0200 Subject: [PATCH 48/96] set back timer to guarantee correct countdown when app is close --- index.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/index.js b/index.js index f00ad8d..17b6c46 100644 --- a/index.js +++ b/index.js @@ -289,8 +289,14 @@ class LegrandMyHome { if (accessory.power) { accessory.RemDuration = _value; + accessory.timerHandle = setInterval(function() { accessory.IrrigationService.setCharacteristic(Characteristic.RemainingDuration,accessory.RemDuration); + accessory.RemDuration--; + if (accessory.RemDuration == 0) + clearInterval(accessory.timerHandle); + }.bind(this),1000); } + } }.bind(this)); @@ -1792,6 +1798,7 @@ class MHIrrigation { } else { + clearInterval(this.timerHandle); this.RemDuration = 0; this.IrrigationService.setCharacteristic(Characteristic.RemainingDuration,this.RemDuration); } From 09c4079d4f6b826231cfe9e78df0be73e22798d2 Mon Sep 17 00:00:00 2001 From: simont77 <26008536+simont77@users.noreply.github.com> Date: Sun, 15 Apr 2018 17:42:59 +0200 Subject: [PATCH 49/96] fix --- index.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/index.js b/index.js index 17b6c46..818b149 100644 --- a/index.js +++ b/index.js @@ -1332,7 +1332,7 @@ class MHPowerMeter { callback(null); }); - if (config.storage == 'fs') + if (this.config.storage == 'fs') this.powerLoggingService = new LegrandMyHome.FakeGatoHistoryService("energy", this,{storage: 'fs'}); else this.powerLoggingService = new LegrandMyHome.FakeGatoHistoryService("energy", this,{storage: 'googleDrive', path: 'homebridge'}); @@ -1414,7 +1414,7 @@ class MHDryContact { switch (this.type) { case 'Contact': this.dryContactService = new Service.ContactSensor(this.name); - if (config.storage == 'fs') + if (this.config.storage == 'fs') this.LoggingService = new LegrandMyHome.FakeGatoHistoryService("door", this,{storage: 'fs'}); else this.LoggingService = new LegrandMyHome.FakeGatoHistoryService("door", this,{storage: 'googleDrive', path: 'homebridge'}); @@ -1466,7 +1466,7 @@ class MHDryContact { return [service, this.dryContactService]; case 'Motion': this.dryContactService = new Service.MotionSensor(this.name); - if (config.storage == 'fs') + if (this.config.storage == 'fs') this.LoggingService = new LegrandMyHome.FakeGatoHistoryService("motion", this,{storage: 'fs'}); else this.LoggingService = new LegrandMyHome.FakeGatoHistoryService("motion", this,{storage: 'googleDrive', path: 'homebridge'}); From 409a83ecedb68e2c5edbbd35cedf8f53aeace136 Mon Sep 17 00:00:00 2001 From: simont77 <26008536+simont77@users.noreply.github.com> Date: Mon, 16 Apr 2018 20:16:06 +0200 Subject: [PATCH 50/96] save last activation, number opening, last reset for door/motion using fakegato --- index.js | 52 +++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 45 insertions(+), 7 deletions(-) diff --git a/index.js b/index.js index 818b149..6da3682 100644 --- a/index.js +++ b/index.js @@ -1394,6 +1394,7 @@ class MHDryContact { this.duration = config.duration || 30; this.firstGet = true; this.lastOpening = 0; + this.lastActivation = 0; this.state = config.state || false; this.log.info(sprintf("LegrandMyHome::MHDryContact create object: %s", this.address)); } @@ -1423,6 +1424,13 @@ class MHDryContact { this.dryContactService.addCharacteristic(LegrandMyHome.ResetTotal); this.dryContactService.addCharacteristic(LegrandMyHome.Char118); this.dryContactService.addCharacteristic(LegrandMyHome.Char119); + this.ExtraPersistedData = this.LoggingService.getExtraPersistedData(); + if (this.ExtraPersistedData != undefined) { + this.numberOpened = this.ExtraPersistedData.numberOpened || 0; + this.lastOpening = this.ExtraPersistedData.lastOpening || 0; + this.lastReset = this.ExtraPersistedData.lastReset || 0; + } + this.dryContactService.getCharacteristic(Characteristic.ContactSensorState) .on('get', (callback) => { this.log.debug(sprintf("getContactSensorState %s = %s",this.address, this.state)); @@ -1435,23 +1443,44 @@ class MHDryContact { this.dryContactService.getCharacteristic(Characteristic.ContactSensorState) .on('change', () => { this.log.debug(sprintf("changeContactSensorState %s = %s",this.address, this.state)); - this.LoggingService.addEntry({time: moment().unix(), status: this.state}); this.lastOpening = moment().unix()-this.LoggingService.getInitialTime(); - if (this.state) - this.numberOpened++; + if (this.state) { + this.ExtraPersistedData = this.LoggingService.getExtraPersistedData(); + if (this.ExtraPersistedData != undefined && this.ExtraPersistedData.numberOpened != undefined) + this.numberOpened = this.ExtraPersistedData.numberOpened + 1; + else + this.numberOpened++; + } + this.LoggingService.setExtraPersistedData({numberOpened:this.numberOpened, lastOpening: this.lastOpening, lastReset:this.lastReset}); + this.LoggingService.addEntry({time: moment().unix(), status: this.state}); }); this.dryContactService.getCharacteristic(LegrandMyHome.ResetTotal) .on('set', (value, callback) => { this.numberOpened = 0; + this.lastReset = value; + this.LoggingService.setExtraPersistedData({numberOpened:this.numberOpened, lastOpening: this.lastOpening, lastReset:this.lastReset}); + this.LoggingService.addEntry({time: moment().unix(), status: this.state}); callback(null); + }) + .on('get', (callback) => { + this.ExtraPersistedData = this.LoggingService.getExtraPersistedData(); + if (this.ExtraPersistedData != undefined ) + this.lastReset = this.ExtraPersistedData.lastReset; + callback(null, this.lastReset); }); this.dryContactService.getCharacteristic(LegrandMyHome.TimesOpened) .on('get', (callback) => { + this.ExtraPersistedData = this.LoggingService.getExtraPersistedData(); + if (this.ExtraPersistedData != undefined ) + this.numberOpened = this.ExtraPersistedData.numberOpened; this.log.debug(sprintf("getNumberOpened = %f",this.numberOpened)); callback(null, this.numberOpened); }); this.dryContactService.getCharacteristic(LegrandMyHome.LastActivation) .on('get', (callback) => { + this.ExtraPersistedData = this.LoggingService.getExtraPersistedData(); + if (this.ExtraPersistedData != undefined ) + this.lastOpening = this.ExtraPersistedData.lastOpening; this.log.debug(sprintf("lastOpening = %f",this.lastOpening)); callback(null, this.lastOpening); }); @@ -1473,7 +1502,11 @@ class MHDryContact { this.dryContactService.addCharacteristic(LegrandMyHome.Sensitivity); this.dryContactService.addCharacteristic(LegrandMyHome.Duration); this.dryContactService.addCharacteristic(LegrandMyHome.LastActivation); - this.dryContactService.setCharacteristic(LegrandMyHome.Duration,this.duration); + this.dryContactService.setCharacteristic(LegrandMyHome.Duration,this.duration); + this.ExtraPersistedData = this.LoggingService.getExtraPersistedData(); + if (this.ExtraPersistedData != undefined) { + this.lastActivation = this.ExtraPersistedData.lastActivation || 0; + } this.dryContactService.getCharacteristic(Characteristic.MotionDetected) .on('get', (callback) => { this.log.debug(sprintf("getMotionSensorState %s = %s",this.address, this.state)); @@ -1486,8 +1519,10 @@ class MHDryContact { this.dryContactService.getCharacteristic(Characteristic.MotionDetected) .on('change', () => { this.log.debug(sprintf("changeMotionSensorState %s = %s",this.address, this.state)); - this.LoggingService.addEntry({time: moment().unix(), status: this.state}); this.lastOpening = moment().unix()-this.LoggingService.getInitialTime(); + this.LoggingService.setExtraPersistedData({lastActivation: this.lastActivation}); + this.LoggingService.addEntry({time: moment().unix(), status: this.state}); + }); this.dryContactService.getCharacteristic(LegrandMyHome.Duration) .on('set', (value, callback) => { @@ -1499,8 +1534,11 @@ class MHDryContact { }); this.dryContactService.getCharacteristic(LegrandMyHome.LastActivation) .on('get', (callback) => { - this.log.debug(sprintf("lastOpening = %f",this.lastOpening)); - callback(null, this.lastOpening); + this.ExtraPersistedData = this.LoggingService.getExtraPersistedData(); + if (this.ExtraPersistedData != undefined ) + this.lastActivation = this.ExtraPersistedData.lastActivation; + this.log.debug(sprintf("lastOpening = %f",this.lastActivation)); + callback(null, this.lastActivation); }); return [service, this.dryContactService, this.LoggingService]; From 85044234e0c29fcf8828c64ac5fe4bb06c6bd8c4 Mon Sep 17 00:00:00 2001 From: simont77 <26008536+simont77@users.noreply.github.com> Date: Tue, 17 Apr 2018 11:02:32 +0200 Subject: [PATCH 51/96] save total consumption and last reset for energy using fakegato --- index.js | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/index.js b/index.js index 6da3682..3de1fee 100644 --- a/index.js +++ b/index.js @@ -458,8 +458,7 @@ class LegrandMyHome { } - onZoneActive(_zone, _state) - { + onZoneActive(_zone, _state) { this.devices.forEach(function(accessory) { if (accessory.alarmService !== undefined) { accessory.zone[_zone] = _state; @@ -1273,30 +1272,19 @@ class MHPowerMeter { this.UUID = UUIDGen.generate(sprintf("powermeter-%s",config.address)); this.log = log; this.refresh = config.refresh || 15; - this.intPower = 0; this.acquiredSamples = 0; - this.averagedSampleForHistory = 600/this.refresh; - + this.lastReset = 0; this.value = 0; this.totalenergy = 0; + this.ExtraPersistedData = {}; this.log.info(sprintf("LegrandMyHome::MHPowerMeter create object")); correctingInterval.setCorrectingInterval(function(){ this.totalenergy = this.totalenergy + this.value * this.refresh / 3600 / 1000; - //this.intPower = this.intPower + this.value; - /*if (this.acquiredSamples { + this.ExtraPersistedData = this.LoggingService.getExtraPersistedData(); + if (this.ExtraPersistedData != undefined ) + this.totalenergy = this.ExtraPersistedData.totalenergy; this.log.debug(sprintf("getConsumptio = %f",this.totalenergy)); callback(null, this.totalenergy); }); this.powerMeterService.getCharacteristic(LegrandMyHome.ResetTotal) .on('set', (value, callback) => { this.totalenergy = 0; + this.lastReset = value; + this.LoggingService.setExtraPersistedData({totalenergy:this.totalenergy, lastReset:this.lastReset}); callback(null); - }); - + }) + .on('get', (callback) => { + this.ExtraPersistedData = this.LoggingService.getExtraPersistedData(); + if (this.ExtraPersistedData != undefined ) + this.lastReset = this.ExtraPersistedData.lastReset; + callback(null, this.lastReset); + }); + if (this.config.storage == 'fs') this.powerLoggingService = new LegrandMyHome.FakeGatoHistoryService("energy", this,{storage: 'fs'}); else @@ -1396,6 +1395,7 @@ class MHDryContact { this.lastOpening = 0; this.lastActivation = 0; this.state = config.state || false; + this.ExtraPersistedData = {}; this.log.info(sprintf("LegrandMyHome::MHDryContact create object: %s", this.address)); } From fe9489483649bf513a77f0737c07b84efc50fc13 Mon Sep 17 00:00:00 2001 From: simont77 <26008536+simont77@users.noreply.github.com> Date: Tue, 17 Apr 2018 22:24:42 +0200 Subject: [PATCH 52/96] version bump --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0fe67a0..9f2cf0d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-myhome-tng", - "version": "0.1.7", + "version": "0.1.8", "description": "Legrand MyHome plugin for homebridge: https://github.com/nfarina/homebridge", "license": "MIT", "keywords": [ From b51cdcc9571c095fd314bbd8bb168e182832ca5e Mon Sep 17 00:00:00 2001 From: simont77 <26008536+simont77@users.noreply.github.com> Date: Wed, 18 Apr 2018 10:12:26 +0200 Subject: [PATCH 53/96] added history to irrigation using "motion", just to show last activation time and save data to googledrive --- index.js | 35 +++++++++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/index.js b/index.js index 3de1fee..76b5d96 100644 --- a/index.js +++ b/index.js @@ -1519,7 +1519,7 @@ class MHDryContact { this.dryContactService.getCharacteristic(Characteristic.MotionDetected) .on('change', () => { this.log.debug(sprintf("changeMotionSensorState %s = %s",this.address, this.state)); - this.lastOpening = moment().unix()-this.LoggingService.getInitialTime(); + this.lastActivation = moment().unix()-this.LoggingService.getInitialTime(); this.LoggingService.setExtraPersistedData({lastActivation: this.lastActivation}); this.LoggingService.addEntry({time: moment().unix(), status: this.state}); @@ -1537,7 +1537,7 @@ class MHDryContact { this.ExtraPersistedData = this.LoggingService.getExtraPersistedData(); if (this.ExtraPersistedData != undefined ) this.lastActivation = this.ExtraPersistedData.lastActivation; - this.log.debug(sprintf("lastOpening = %f",this.lastActivation)); + this.log.debug(sprintf("lastActivation = %f",this.lastActivation)); callback(null, this.lastActivation); }); @@ -1788,6 +1788,9 @@ class MHIrrigation { this.bus = parseInt(address[0]); this.ambient = parseInt(address[1]); this.pl = parseInt(address[2]); + this.lastActivation = 0; + this.ExtraPersistedData = {}; + this.firstGet = true; } getServices() { @@ -1801,8 +1804,12 @@ class MHIrrigation { this.IrrigationService = new Service.Valve(this.name); // just to make the irrigation icon show in Eve, real history signature needed - this.LoggingService = new LegrandMyHome.FakeGatoHistoryService("motion", this, {size: 10, disableTimer: true}); - + this.IrrigationService.addCharacteristic(LegrandMyHome.LastActivation); + this.LoggingService = new LegrandMyHome.FakeGatoHistoryService("motion", this,{storage: 'fs'}); + this.ExtraPersistedData = this.LoggingService.getExtraPersistedData(); + if (this.ExtraPersistedData != undefined) { + this.lastActivation = this.ExtraPersistedData.lastActivation || 0; + } this.IrrigationService.setCharacteristic(Characteristic.ValveType,1); this.IrrigationService.setCharacteristic(Characteristic.SetDuration,this.timer); @@ -1818,7 +1825,7 @@ class MHIrrigation { { this.mh.relayCommand(this.address,this.power); } - + callback(null); }) .on('get', (callback) => { @@ -1827,6 +1834,10 @@ class MHIrrigation { }); this.IrrigationService.getCharacteristic(Characteristic.InUse) .on('get', (callback) => { + if (this.firstGet) { + this.firstGet = false; + this.LoggingService.addEntry({time: moment().unix(), status: this.power}); + } callback(null, this.power); }) .on('change',() => { @@ -1839,7 +1850,11 @@ class MHIrrigation { clearInterval(this.timerHandle); this.RemDuration = 0; this.IrrigationService.setCharacteristic(Characteristic.RemainingDuration,this.RemDuration); - } + } + this.log.debug(sprintf("changeIrrigation %s = %s",this.address, this.power)); + this.lastActivation = moment().unix()-this.LoggingService.getInitialTime(); + this.LoggingService.setExtraPersistedData({lastActivation: this.lastActivation}); + this.LoggingService.addEntry({time: moment().unix(), status: this.power}); }); this.IrrigationService.getCharacteristic(Characteristic.SetDuration) .on('set', (time, callback) => { @@ -1857,6 +1872,14 @@ class MHIrrigation { .on('get', (callback) => { callback(null, this.RemDuration); }); + this.IrrigationService.getCharacteristic(LegrandMyHome.LastActivation) + .on('get', (callback) => { + this.ExtraPersistedData = this.LoggingService.getExtraPersistedData(); + if (this.ExtraPersistedData != undefined ) + this.lastActivation = this.ExtraPersistedData.lastActivation; + this.log.debug(sprintf("lastActivation = %f",this.lastActivation)); + callback(null, this.lastActivation); + }); return [service, this.IrrigationService, this.LoggingService]; } } \ No newline at end of file From 957124a794bc555d57aeed365575d5d37f7dd45b Mon Sep 17 00:00:00 2001 From: simont77 <26008536+simont77@users.noreply.github.com> Date: Thu, 19 Apr 2018 10:04:45 +0200 Subject: [PATCH 54/96] update fakegato dependencies --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0fe67a0..b6135aa 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,6 @@ "sprintf-js": "^1.0.3", "moment": "^2.18.1", "correcting-interval":"^2.0.0", - "fakegato-history":"^0.4.0" + "fakegato-history":"^0.5.0" } } From dd371a7c8655b8646d91870dd2701a51d2b5294f Mon Sep 17 00:00:00 2001 From: simont77 <26008536+simont77@users.noreply.github.com> Date: Sun, 22 Apr 2018 17:40:45 +0200 Subject: [PATCH 55/96] fix --- index.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/index.js b/index.js index 76b5d96..969fa44 100644 --- a/index.js +++ b/index.js @@ -1281,7 +1281,7 @@ class MHPowerMeter { this.log.info(sprintf("LegrandMyHome::MHPowerMeter create object")); correctingInterval.setCorrectingInterval(function(){ this.totalenergy = this.totalenergy + this.value * this.refresh / 3600 / 1000; - this.LoggingService.setExtraPersistedData({totalenergy:this.totalenergy, lastReset:this.lastReset}); + this.powerLoggingService.setExtraPersistedData({totalenergy:this.totalenergy, lastReset:this.lastReset}); this.powerMeterService.getCharacteristic(LegrandMyHome.CurrentPowerConsumption).getValue(null); this.powerMeterService.getCharacteristic(LegrandMyHome.TotalConsumption).getValue(null); this.powerLoggingService.addEntry({time: moment().unix(), power:this.value}); @@ -1311,7 +1311,7 @@ class MHPowerMeter { }); this.powerMeterService.getCharacteristic(LegrandMyHome.TotalConsumption) .on('get', (callback) => { - this.ExtraPersistedData = this.LoggingService.getExtraPersistedData(); + this.ExtraPersistedData = this.powerLoggingService.getExtraPersistedData(); if (this.ExtraPersistedData != undefined ) this.totalenergy = this.ExtraPersistedData.totalenergy; this.log.debug(sprintf("getConsumptio = %f",this.totalenergy)); @@ -1321,11 +1321,11 @@ class MHPowerMeter { .on('set', (value, callback) => { this.totalenergy = 0; this.lastReset = value; - this.LoggingService.setExtraPersistedData({totalenergy:this.totalenergy, lastReset:this.lastReset}); + this.powerLoggingService.setExtraPersistedData({totalenergy:this.totalenergy, lastReset:this.lastReset}); callback(null); }) .on('get', (callback) => { - this.ExtraPersistedData = this.LoggingService.getExtraPersistedData(); + this.ExtraPersistedData = this.powerLoggingService.getExtraPersistedData(); if (this.ExtraPersistedData != undefined ) this.lastReset = this.ExtraPersistedData.lastReset; callback(null, this.lastReset); From 831970312b73a5fe55db9f2be884c2c15af43670 Mon Sep 17 00:00:00 2001 From: simont77 <26008536+simont77@users.noreply.github.com> Date: Sun, 22 Apr 2018 17:57:14 +0200 Subject: [PATCH 56/96] default googledrive persistance for irrigation --- index.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/index.js b/index.js index 969fa44..0dfa55d 100644 --- a/index.js +++ b/index.js @@ -1805,7 +1805,10 @@ class MHIrrigation { // just to make the irrigation icon show in Eve, real history signature needed this.IrrigationService.addCharacteristic(LegrandMyHome.LastActivation); - this.LoggingService = new LegrandMyHome.FakeGatoHistoryService("motion", this,{storage: 'fs'}); + if (this.config.storage == 'fs') + this.LoggingService = new LegrandMyHome.FakeGatoHistoryService("motion", this,{storage: 'fs'}); + else + this.LoggingService = new LegrandMyHome.FakeGatoHistoryService("motion", this,{storage: 'googleDrive', path: 'homebridge'}); this.ExtraPersistedData = this.LoggingService.getExtraPersistedData(); if (this.ExtraPersistedData != undefined) { this.lastActivation = this.ExtraPersistedData.lastActivation || 0; From 8941e34566be9a67bba1eae7752fa1804a018ae2 Mon Sep 17 00:00:00 2001 From: simont77 <26008536+simont77@users.noreply.github.com> Date: Sun, 22 Apr 2018 19:48:58 +0200 Subject: [PATCH 57/96] fix for not overloading the gateway --- index.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/index.js b/index.js index 0dfa55d..90b485c 100644 --- a/index.js +++ b/index.js @@ -1846,7 +1846,8 @@ class MHIrrigation { .on('change',() => { if (this.power) { - this.mh.getRelayDuration(this.address); + setTimeout(function () { + this.mh.getRelayDuration(this.address)}.bind(this),1000); } else { From 5ecb886d7a30aa08f84943402829f28ef420028e Mon Sep 17 00:00:00 2001 From: simont77 <26008536+simont77@users.noreply.github.com> Date: Sun, 22 Apr 2018 20:44:47 +0200 Subject: [PATCH 58/96] fix for timed relay command --- index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index 90b485c..c998fae 100644 --- a/index.js +++ b/index.js @@ -845,7 +845,7 @@ class MHTimedRelay { /* Custom frame support */ if (this.power && this.timer !=0) { - this.mh.relayTimedOn(this.address,this.timer/3600,this.timer/60,this.timer); + this.mh.relayTimedOn(this.address,this.timer/3600,this.timer/60,this.timer%60); } else { @@ -1822,7 +1822,7 @@ class MHIrrigation { this.power = _value; if (this.power) { - this.mh.relayTimedOn(this.address,this.timer/3600,this.timer/60,this.timer); + this.mh.relayTimedOn(this.address,this.timer/3600,this.timer/60,this.timer%60); } else { From 3ba3b9faf7170d2cd4c804fadad1223cbf428208 Mon Sep 17 00:00:00 2001 From: simont77 <26008536+simont77@users.noreply.github.com> Date: Tue, 24 Apr 2018 09:03:00 +0200 Subject: [PATCH 59/96] fix for persistance of total energy --- index.js | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index c998fae..2d3dcad 100644 --- a/index.js +++ b/index.js @@ -1277,11 +1277,20 @@ class MHPowerMeter { this.lastReset = 0; this.value = 0; this.totalenergy = 0; + this.totalenergytemp = 0; this.ExtraPersistedData = {}; this.log.info(sprintf("LegrandMyHome::MHPowerMeter create object")); correctingInterval.setCorrectingInterval(function(){ - this.totalenergy = this.totalenergy + this.value * this.refresh / 3600 / 1000; - this.powerLoggingService.setExtraPersistedData({totalenergy:this.totalenergy, lastReset:this.lastReset}); + this.ExtraPersistedData = this.powerLoggingService.getExtraPersistedData(); + if (this.ExtraPersistedData != undefined ) { + this.totalenergy = this.ExtraPersistedData.totalenergy + this.totalenergytemp + this.value * this.refresh / 3600 / 1000; + this.powerLoggingService.setExtraPersistedData({totalenergy:this.totalenergy, lastReset:this.lastReset}); + this.totalenergytemp = 0; + } + else { + this.totalenergytemp = this.totalenergytemp + this.value * this.refresh / 3600 / 1000; + this.totalenergy = this.totalenergytemp; + } this.powerMeterService.getCharacteristic(LegrandMyHome.CurrentPowerConsumption).getValue(null); this.powerMeterService.getCharacteristic(LegrandMyHome.TotalConsumption).getValue(null); this.powerLoggingService.addEntry({time: moment().unix(), power:this.value}); From d9dfb69a01ef14873cdd2380d385add87f34eca2 Mon Sep 17 00:00:00 2001 From: simont77 <26008536+simont77@users.noreply.github.com> Date: Fri, 27 Apr 2018 10:37:41 +0200 Subject: [PATCH 60/96] check if history was loaded for energy before setting extra persisted data --- index.js | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/index.js b/index.js index 2d3dcad..62595b1 100644 --- a/index.js +++ b/index.js @@ -1281,11 +1281,16 @@ class MHPowerMeter { this.ExtraPersistedData = {}; this.log.info(sprintf("LegrandMyHome::MHPowerMeter create object")); correctingInterval.setCorrectingInterval(function(){ - this.ExtraPersistedData = this.powerLoggingService.getExtraPersistedData(); - if (this.ExtraPersistedData != undefined ) { - this.totalenergy = this.ExtraPersistedData.totalenergy + this.totalenergytemp + this.value * this.refresh / 3600 / 1000; - this.powerLoggingService.setExtraPersistedData({totalenergy:this.totalenergy, lastReset:this.lastReset}); + if (this.powerLoggingService.loaded) { + this.ExtraPersistedData = this.powerLoggingService.getExtraPersistedData(); + if (this.ExtraPersistedData != undefined ) { + this.totalenergy = this.ExtraPersistedData.totalenergy + this.totalenergytemp + this.value * this.refresh / 3600 / 1000; + } + else { + this.totalenergy = this.totalenergytemp + this.value * this.refresh / 3600 / 1000; + } this.totalenergytemp = 0; + this.powerLoggingService.setExtraPersistedData({totalenergy:this.totalenergy, lastReset:this.lastReset}); } else { this.totalenergytemp = this.totalenergytemp + this.value * this.refresh / 3600 / 1000; @@ -1856,7 +1861,8 @@ class MHIrrigation { if (this.power) { setTimeout(function () { - this.mh.getRelayDuration(this.address)}.bind(this),1000); + this.mh.getRelayDuration(this.address); + }.bind(this),1000); } else { From 74f10963bfc8bfd6b59ce487db935fb5d009f46c Mon Sep 17 00:00:00 2001 From: simont77 <26008536+simont77@users.noreply.github.com> Date: Sun, 29 Apr 2018 17:45:17 +0200 Subject: [PATCH 61/96] fix --- index.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/index.js b/index.js index 62595b1..ff16fe9 100644 --- a/index.js +++ b/index.js @@ -1281,16 +1281,18 @@ class MHPowerMeter { this.ExtraPersistedData = {}; this.log.info(sprintf("LegrandMyHome::MHPowerMeter create object")); correctingInterval.setCorrectingInterval(function(){ - if (this.powerLoggingService.loaded) { + if (this.powerLoggingService.isHistoryLoaded()) { this.ExtraPersistedData = this.powerLoggingService.getExtraPersistedData(); if (this.ExtraPersistedData != undefined ) { this.totalenergy = this.ExtraPersistedData.totalenergy + this.totalenergytemp + this.value * this.refresh / 3600 / 1000; + this.powerLoggingService.setExtraPersistedData({totalenergy:this.totalenergy, lastReset:this.ExtraPersistedData.lastReset}); } else { this.totalenergy = this.totalenergytemp + this.value * this.refresh / 3600 / 1000; + this.powerLoggingService.setExtraPersistedData({totalenergy:this.totalenergy, lastReset:0}); } this.totalenergytemp = 0; - this.powerLoggingService.setExtraPersistedData({totalenergy:this.totalenergy, lastReset:this.lastReset}); + } else { this.totalenergytemp = this.totalenergytemp + this.value * this.refresh / 3600 / 1000; @@ -1335,7 +1337,7 @@ class MHPowerMeter { .on('set', (value, callback) => { this.totalenergy = 0; this.lastReset = value; - this.powerLoggingService.setExtraPersistedData({totalenergy:this.totalenergy, lastReset:this.lastReset}); + this.powerLoggingService.setExtraPersistedData({totalenergy:this.totalenergy,lastReset:this.lastReset}); callback(null); }) .on('get', (callback) => { From b362b64b76750258f4a2c32e1ea3f219ac944346 Mon Sep 17 00:00:00 2001 From: simont77 <26008536+simont77@users.noreply.github.com> Date: Sun, 29 Apr 2018 17:47:04 +0200 Subject: [PATCH 62/96] update fakegato dependency --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index bd39cbd..9688c62 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,6 @@ "sprintf-js": "^1.0.3", "moment": "^2.18.1", "correcting-interval":"^2.0.0", - "fakegato-history":"^0.5.0" + "fakegato-history":"^0.5.1" } } From 41407cc53f076b0662ea3d12c686c8d99b6f63c7 Mon Sep 17 00:00:00 2001 From: simont77 <26008536+simont77@users.noreply.github.com> Date: Sun, 29 Apr 2018 17:47:40 +0200 Subject: [PATCH 63/96] 0.1.9 --- package.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 9688c62..7d73f30 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-myhome-tng", - "version": "0.1.8", + "version": "0.1.9", "description": "Legrand MyHome plugin for homebridge: https://github.com/nfarina/homebridge", "license": "MIT", "keywords": [ @@ -23,7 +23,7 @@ "sha256": "^0.2.0", "sprintf-js": "^1.0.3", "moment": "^2.18.1", - "correcting-interval":"^2.0.0", - "fakegato-history":"^0.5.1" + "correcting-interval": "^2.0.0", + "fakegato-history": "^0.5.1" } } From 5c1d25fdbacae8bcfbb149a384c239987fea2358 Mon Sep 17 00:00:00 2001 From: simont77 <26008536+simont77@users.noreply.github.com> Date: Sat, 5 May 2018 12:12:41 +0200 Subject: [PATCH 64/96] disable fakegato timer for irrigation --- index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index ff16fe9..866518b 100644 --- a/index.js +++ b/index.js @@ -1822,9 +1822,9 @@ class MHIrrigation { // just to make the irrigation icon show in Eve, real history signature needed this.IrrigationService.addCharacteristic(LegrandMyHome.LastActivation); if (this.config.storage == 'fs') - this.LoggingService = new LegrandMyHome.FakeGatoHistoryService("motion", this,{storage: 'fs'}); + this.LoggingService = new LegrandMyHome.FakeGatoHistoryService("motion", this,{storage: 'fs', disableTimer: true}); else - this.LoggingService = new LegrandMyHome.FakeGatoHistoryService("motion", this,{storage: 'googleDrive', path: 'homebridge'}); + this.LoggingService = new LegrandMyHome.FakeGatoHistoryService("motion", this,{storage: 'googleDrive', path: 'homebridge', disableTimer: true}); this.ExtraPersistedData = this.LoggingService.getExtraPersistedData(); if (this.ExtraPersistedData != undefined) { this.lastActivation = this.ExtraPersistedData.lastActivation || 0; From 61284620a0ade58213d339dd1613b3c9dc7f0bc2 Mon Sep 17 00:00:00 2001 From: simont77 <26008536+simont77@users.noreply.github.com> Date: Sat, 5 May 2018 12:13:37 +0200 Subject: [PATCH 65/96] 0.1.10 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 7d73f30..6e4ad87 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-myhome-tng", - "version": "0.1.9", + "version": "0.1.10", "description": "Legrand MyHome plugin for homebridge: https://github.com/nfarina/homebridge", "license": "MIT", "keywords": [ From 0665c720b6922bef226a7b686bd680858a05a30b Mon Sep 17 00:00:00 2001 From: simont77 <26008536+simont77@users.noreply.github.com> Date: Tue, 15 May 2018 08:43:42 +0200 Subject: [PATCH 66/96] support for scenario enable/disable commands --- lib/mhclient.js | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/lib/mhclient.js b/lib/mhclient.js index 4e920d3..4e8b000 100755 --- a/lib/mhclient.js +++ b/lib/mhclient.js @@ -154,6 +154,11 @@ class MyHomeClient { if (_forced == 1) this.command.send(sprintf("*3*2*#%d##",_address)); } + + enableScenarioCommand(_address,_status) { + if (_address == "") return; + this.command.send(sprintf("*17*%d*%s##",(_status)?3:4,_address)); + } setSetPoint(_address,_temperature) { // Standard thermostat *4*40*%02d##*#4*#%02d*#14*%04d*3 @@ -314,6 +319,7 @@ class MyHomeClient { if (this.parent != null && this.parent.onMonitor != null && typeof(this.parent.onDryContact) == 'function') this.parent.onDryContact(address,value); debug(sprintf("DRYCONTACT %s ADDRESS %s",value,address)); } + // AUX: *9*[0,9]*## OFF // AUX: *9*1*## ON extract = frame.match(/^\*9\*(\d)\*(\d)$/); @@ -328,6 +334,21 @@ class MyHomeClient { this.parent.onAUX(address,value); debug(sprintf("AUX %s ADDRESS %s",value,address)); } + + // Scenario: *17*3*## Enable + // Scenario: *17*4*## Disable + extract = frame.match(/^\*17\*(\d)\*(\d+)$/); + if (extract) { + let value = false; + if (parseInt(extract[1],10) == 3) + value = true; + if (parseInt(extract[1],10) == 4) + value = false; + let address = parseInt(extract[2],10); + if (this.parent != null && this.parent.onMonitor != null && typeof(this.parent.onScenario) == 'function') + this.parent.onScenario(address,value); + debug(sprintf("Scenario %s ADDRESS %s",value,address)); + } //powermeter extract = frame.match(/^\*#3\*10\*3\*(\d+)$/); From 5048fd3bda9485425016aa7b980bf1894d4478d1 Mon Sep 17 00:00:00 2001 From: simont77 <26008536+simont77@users.noreply.github.com> Date: Sat, 19 May 2018 16:43:14 +0200 Subject: [PATCH 67/96] added MHScenario class and support --- index.js | 64 +++++++++++++++++++++++++++++++++++++++++++++---- lib/mhclient.js | 4 ++++ 2 files changed, 63 insertions(+), 5 deletions(-) diff --git a/index.js b/index.js index 866518b..5ae91c9 100644 --- a/index.js +++ b/index.js @@ -181,7 +181,7 @@ class LegrandMyHome { if (accessory.accessory == 'MHExternalThermometer') this.devices.push(new MHThermometer(this.log,accessory)); if (accessory.accessory == 'MHDryContact') this.devices.push(new MHDryContact(this.log,accessory)); if (accessory.accessory == 'MHAux') this.devices.push(new MHAux(this.log,accessory)); - /* if (accessory.accessory == 'MHButton') this.devices.push(new MHButton(this.log,accessory)) */ + if (accessory.accessory == 'MHScenario') this.devices.push(new MHScenario(this.log,accessory)) if (accessory.accessory == 'MHPowerMeter') this.devices.push(new MHPowerMeter(this.log,accessory)); if (accessory.accessory == 'MHAlarm') this.devices.push(new MHAlarm(this.log,accessory)); if (accessory.accessory == 'MHControlledLoad') this.devices.push(new MHControlledLoad(this.log,accessory)); @@ -198,9 +198,12 @@ class LegrandMyHome { onConnect() { this.devices.forEach(function (accessory) { - if (accessory.thermostatService !== undefined) this.controller.getThermostatStatus(accessory.address); - if (accessory.contactSensorService !== undefined || accessory.dryContactService !== undefined) this.controller.getContactState(accessory.address); - if (accessory.windowCoveringPlusService !== undefined) this.controller.getAdvancedBlindState(accessory.address); + if (accessory.thermostatService !== undefined) + this.controller.getThermostatStatus(accessory.address); + if (accessory.contactSensorService !== undefined || accessory.dryContactService !== undefined) + this.controller.getContactState(accessory.address); + if (accessory.windowCoveringPlusService !== undefined) + this.controller.getAdvancedBlindState(accessory.address); if (accessory.lightBulbService !== undefined && accessory.pul == true) this.controller.getRelayState(accessory.address); if (accessory.rainService !== undefined && accessory.pul == true) @@ -209,6 +212,8 @@ class LegrandMyHome { this.controller.getRelayState(accessory.address); if (accessory.alarmService !== undefined) this.controller.getAlarmState(); + if (accessory.scenarioService !== undefined) + this.controller.getScenarioState(accessory.address); }.bind(this)); } @@ -235,7 +240,6 @@ class LegrandMyHome { } if (accessory.address == _address && accessory.IrrigationService !== undefined) { accessory.power = _onoff; - //accessory.askDuration = true; accessory.IrrigationService.getCharacteristic(Characteristic.Active).getValue(null); accessory.IrrigationService.getCharacteristic(Characteristic.InUse).getValue(null); } @@ -283,6 +287,16 @@ class LegrandMyHome { } }.bind(this)); } + + onScenario(_address,_state) { + this.devices.forEach(function(accessory) { + if (accessory.scenarioService !== undefined && accessory.address == _address) { + accessory.state = _state; + accessory.scenarioService.getCharacteristic(Characteristic.On).getValue(null); + } + }.bind(this)); + } + onRelayDuration(_address,_value) { this.devices.forEach(function(accessory) { if (accessory.address == _address && accessory.IrrigationService !== undefined) { @@ -1393,6 +1407,45 @@ class MHButton { } +class MHScenario { + constructor(log, config) { + this.config = config || {}; + this.mh = config.parent.controller; + this.name = config.name; + this.address = config.address; + this.displayName = config.name; + this.UUID = UUIDGen.generate(sprintf("scenario-%s",config.address)); + this.log = log; + + this.state = 0; + this.log.info(sprintf("LegrandMyHome::MHScenario create object: %s", this.address)); + } + + getServices() { + var service = new Service.AccessoryInformation(); + service.setCharacteristic(Characteristic.Name, this.name) + .setCharacteristic(Characteristic.Manufacturer, "Simone Tisa") + .setCharacteristic(Characteristic.Model, "Scenario") + .setCharacteristic(Characteristic.FirmwareRevision, version) + .setCharacteristic(Characteristic.SerialNumber, "Address " + this.address); + + this.scenarioService = new Service.Switch(this.name); + this.scenarioService.getCharacteristic(Characteristic.On) + .on('set', (value,callback) => { + this.state = value; + this.mh.enableScenarioCommand(this.address,this.state); + this.log.debug(sprintf("setOn %s = %s",this.address, this.state)); + callback(null); + }) + .on('get', (callback) => { + this.log.debug(sprintf("getOn %s",this.address)); + callback(null,this.state); + }); + return [service, this.scenarioService]; + } + +} + class MHDryContact { constructor(log, config) { @@ -1901,6 +1954,7 @@ class MHIrrigation { this.log.debug(sprintf("lastActivation = %f",this.lastActivation)); callback(null, this.lastActivation); }); + return [service, this.IrrigationService, this.LoggingService]; } } \ No newline at end of file diff --git a/lib/mhclient.js b/lib/mhclient.js index 4e8b000..a7071a8 100755 --- a/lib/mhclient.js +++ b/lib/mhclient.js @@ -447,6 +447,10 @@ class MyHomeClient { getContactState(_address) { this.command.send(sprintf("*#25*3%d##",_address)); } + + getScenarioState(_address) { + this.command.send(sprintf("*#17*%d##",_address)); + } getRelayState(_address) { this.command.send(sprintf("*#1*%s##",this._slashesToAddress(_address))); From 2f14ac34bac8cc10a4676d5da0aeca2e959534a8 Mon Sep 17 00:00:00 2001 From: simont77 <26008536+simont77@users.noreply.github.com> Date: Sat, 19 May 2018 16:44:32 +0200 Subject: [PATCH 68/96] 0.1.11 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6e4ad87..54d25aa 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-myhome-tng", - "version": "0.1.10", + "version": "0.1.11", "description": "Legrand MyHome plugin for homebridge: https://github.com/nfarina/homebridge", "license": "MIT", "keywords": [ From 793bb9a2e582e5351c0fde7b888dbe78a4439a7f Mon Sep 17 00:00:00 2001 From: simont77 <26008536+simont77@users.noreply.github.com> Date: Sat, 19 May 2018 17:44:52 +0200 Subject: [PATCH 69/96] prettify --- index.js | 1002 +++++++++++++++++++++++------------------------ lib/mhclient.js | 474 +++++++++++----------- 2 files changed, 725 insertions(+), 751 deletions(-) diff --git a/index.js b/index.js index 5ae91c9..c36d153 100644 --- a/index.js +++ b/index.js @@ -1,6 +1,6 @@ /*jshint esversion: 6,node: true,-W041: false */ -var path = require("path"); -var mh = require(path.join(__dirname,'/lib/mhclient')); +var path = require("path"); +var mh = require(path.join(__dirname, '/lib/mhclient')); var sprintf = require("sprintf-js").sprintf, inherits = require("util").inherits; var events = require('events'), util = require('util'), fs = require('fs'); var Accessory, Characteristic, Service, UUIDGen; @@ -16,7 +16,7 @@ module.exports = function (homebridge) { var FakeGatoHistoryService = require('fakegato-history')(homebridge); /* Try to map Elgato custom vars */ - LegrandMyHome.CurrentPowerConsumption = function() { + LegrandMyHome.CurrentPowerConsumption = function () { Characteristic.call(this, 'Consumption', 'E863F10D-079E-48FF-8F27-9C2605A29F52'); this.setProps({ format: Characteristic.Formats.UINT16, @@ -27,11 +27,11 @@ module.exports = function (homebridge) { perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY] }); this.value = this.getDefaultValue(); - }; - LegrandMyHome.CurrentPowerConsumption.UUID = 'E863F10D-079E-48FF-8F27-9C2605A29F52'; + }; + LegrandMyHome.CurrentPowerConsumption.UUID = 'E863F10D-079E-48FF-8F27-9C2605A29F52'; inherits(LegrandMyHome.CurrentPowerConsumption, Characteristic); - LegrandMyHome.TotalConsumption = function() { + LegrandMyHome.TotalConsumption = function () { Characteristic.call(this, 'Energy', 'E863F10C-079E-48FF-8F27-9C2605A29F52'); this.setProps({ format: Characteristic.Formats.FLOAT, @@ -42,22 +42,22 @@ module.exports = function (homebridge) { perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY] }); this.value = this.getDefaultValue(); - }; - LegrandMyHome.TotalConsumption.UUID = 'E863F10C-079E-48FF-8F27-9C2605A29F52'; + }; + LegrandMyHome.TotalConsumption.UUID = 'E863F10C-079E-48FF-8F27-9C2605A29F52'; inherits(LegrandMyHome.TotalConsumption, Characteristic); - LegrandMyHome.ResetTotal = function() { + LegrandMyHome.ResetTotal = function () { Characteristic.call(this, 'Reset', 'E863F112-079E-48FF-8F27-9C2605A29F52'); this.setProps({ format: Characteristic.Formats.UINT32, perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY, Characteristic.Perms.WRITE] }); this.value = this.getDefaultValue(); - }; - LegrandMyHome.ResetTotal.UUID = 'E863F112-079E-48FF-8F27-9C2605A29F52'; + }; + LegrandMyHome.ResetTotal.UUID = 'E863F112-079E-48FF-8F27-9C2605A29F52'; inherits(LegrandMyHome.ResetTotal, Characteristic); - LegrandMyHome.Sensitivity = function() { + LegrandMyHome.Sensitivity = function () { Characteristic.call(this, 'Sensitivity', 'E863F120-079E-48FF-8F27-9C2605A29F52'); this.setProps({ format: Characteristic.Formats.UINT16, @@ -67,11 +67,11 @@ module.exports = function (homebridge) { perms: [Characteristic.Perms.READ, Characteristic.Perms.WRITE] }); this.value = this.getDefaultValue(); - }; - LegrandMyHome.Sensitivity.UUID = 'E863F120-079E-48FF-8F27-9C2605A29F52'; + }; + LegrandMyHome.Sensitivity.UUID = 'E863F120-079E-48FF-8F27-9C2605A29F52'; inherits(LegrandMyHome.Sensitivity, Characteristic); - LegrandMyHome.Duration = function() { + LegrandMyHome.Duration = function () { Characteristic.call(this, 'Duration', 'E863F12D-079E-48FF-8F27-9C2605A29F52'); this.setProps({ format: Characteristic.Formats.UINT16, @@ -81,75 +81,75 @@ module.exports = function (homebridge) { perms: [Characteristic.Perms.READ, Characteristic.Perms.WRITE] }); this.value = this.getDefaultValue(); - }; - LegrandMyHome.Duration.UUID = 'E863F12D-079E-48FF-8F27-9C2605A29F52'; + }; + LegrandMyHome.Duration.UUID = 'E863F12D-079E-48FF-8F27-9C2605A29F52'; inherits(LegrandMyHome.Duration, Characteristic); - LegrandMyHome.LastActivation = function() { + LegrandMyHome.LastActivation = function () { Characteristic.call(this, 'LastActivation', 'E863F11A-079E-48FF-8F27-9C2605A29F52'); this.setProps({ format: Characteristic.Formats.UINT32, perms: [Characteristic.Perms.READ, Characteristic.Perms.WRITE, Characteristic.Perms.NOTIFY] }); this.value = this.getDefaultValue(); - }; - LegrandMyHome.LastActivation.UUID = 'E863F11A-079E-48FF-8F27-9C2605A29F52'; + }; + LegrandMyHome.LastActivation.UUID = 'E863F11A-079E-48FF-8F27-9C2605A29F52'; inherits(LegrandMyHome.LastActivation, Characteristic); - LegrandMyHome.TimesOpened = function() { + LegrandMyHome.TimesOpened = function () { Characteristic.call(this, 'TimesOpened', 'E863F129-079E-48FF-8F27-9C2605A29F52'); this.setProps({ format: Characteristic.Formats.UINT32, perms: [Characteristic.Perms.READ, Characteristic.Perms.WRITE, Characteristic.Perms.NOTIFY] }); this.value = this.getDefaultValue(); - }; - LegrandMyHome.TimesOpened.UUID = 'E863F129-079E-48FF-8F27-9C2605A29F52'; + }; + LegrandMyHome.TimesOpened.UUID = 'E863F129-079E-48FF-8F27-9C2605A29F52'; inherits(LegrandMyHome.TimesOpened, Characteristic); - LegrandMyHome.Char118 = function() { + LegrandMyHome.Char118 = function () { Characteristic.call(this, 'Char118', 'E863F118-079E-48FF-8F27-9C2605A29F52'); this.setProps({ format: Characteristic.Formats.UINT32, perms: [Characteristic.Perms.READ, Characteristic.Perms.WRITE, Characteristic.Perms.NOTIFY] }); this.value = this.getDefaultValue(); - }; - LegrandMyHome.Char118.UUID = 'E863F118-079E-48FF-8F27-9C2605A29F52'; + }; + LegrandMyHome.Char118.UUID = 'E863F118-079E-48FF-8F27-9C2605A29F52'; inherits(LegrandMyHome.Char118, Characteristic); - LegrandMyHome.Char119 = function() { + LegrandMyHome.Char119 = function () { Characteristic.call(this, 'Char119', 'E863F119-079E-48FF-8F27-9C2605A29F52'); this.setProps({ format: Characteristic.Formats.UINT32, perms: [Characteristic.Perms.READ, Characteristic.Perms.WRITE, Characteristic.Perms.NOTIFY] }); this.value = this.getDefaultValue(); - }; - LegrandMyHome.Char119.UUID = 'E863F119-079E-48FF-8F27-9C2605A29F52'; + }; + LegrandMyHome.Char119.UUID = 'E863F119-079E-48FF-8F27-9C2605A29F52'; inherits(LegrandMyHome.Char119, Characteristic); - LegrandMyHome.PowerMeterService = function(displayName, subtype) { - Service.call(this, displayName, '00000001-0000-1777-8000-775D67EC4377', subtype); - this.addCharacteristic(LegrandMyHome.CurrentPowerConsumption); - this.addCharacteristic(LegrandMyHome.TotalConsumption); - this.addCharacteristic(LegrandMyHome.ResetTotal); + LegrandMyHome.PowerMeterService = function (displayName, subtype) { + Service.call(this, displayName, '00000001-0000-1777-8000-775D67EC4377', subtype); + this.addCharacteristic(LegrandMyHome.CurrentPowerConsumption); + this.addCharacteristic(LegrandMyHome.TotalConsumption); + this.addCharacteristic(LegrandMyHome.ResetTotal); }; inherits(LegrandMyHome.PowerMeterService, Service); - LegrandMyHome.FakeGatoHistoryService=FakeGatoHistoryService; + LegrandMyHome.FakeGatoHistoryService = FakeGatoHistoryService; inherits(LegrandMyHome.FakeGatoHistoryService, Service); - LegrandMyHome.ControlledLoadService = function(displayName, subtype) { - Service.call(this, displayName, 'D43133F2-9BDE-4731-9FF2-B427189DCB4A', subtype); - this.addCharacteristic(Characteristic.OutletInUse); - this.addCharacteristic(Characteristic.Active); + LegrandMyHome.ControlledLoadService = function (displayName, subtype) { + Service.call(this, displayName, 'D43133F2-9BDE-4731-9FF2-B427189DCB4A', subtype); + this.addCharacteristic(Characteristic.OutletInUse); + this.addCharacteristic(Characteristic.Active); }; inherits(LegrandMyHome.ControlledLoadService, Service); - LegrandMyHome.RainSensorService = function(displayName, subtype) { - Service.call(this, displayName, '9018CDC8-DEF9-49D5-A969-63F8CCAAB1A6', subtype); - this.addCharacteristic(Characteristic.CurrentRelativeHumidity); + LegrandMyHome.RainSensorService = function (displayName, subtype) { + Service.call(this, displayName, '9018CDC8-DEF9-49D5-A969-63F8CCAAB1A6', subtype); + this.addCharacteristic(Characteristic.CurrentRelativeHumidity); }; inherits(LegrandMyHome.RainSensorService, Service); @@ -170,23 +170,23 @@ class LegrandMyHome { this.config.devices.forEach(function (accessory) { this.log.info("LegrandMyHome: adds accessory"); accessory.parent = this; - if (accessory.accessory == 'MHRelay') this.devices.push(new MHRelay(this.log,accessory)); - if (accessory.accessory == 'MHBlind') this.devices.push(new MHBlind(this.log,accessory)); - if (accessory.accessory == 'MHBlindAdvanced') this.devices.push(new MHBlindAdvanced(this.log,accessory)); - if (accessory.accessory == 'MHOutlet') this.devices.push(new MHRelay(this.log,accessory)); - if (accessory.accessory == 'MHTimedRelay') this.devices.push(new MHTimedRelay(this.log,accessory)); - if (accessory.accessory == 'MHRain') this.devices.push(new MHRain(this.log,accessory)); - if (accessory.accessory == 'MHDimmer') this.devices.push(new MHDimmer(this.log,accessory)); - if (accessory.accessory == 'MHThermostat') this.devices.push(new MHThermostat(this.log,accessory)); - if (accessory.accessory == 'MHExternalThermometer') this.devices.push(new MHThermometer(this.log,accessory)); - if (accessory.accessory == 'MHDryContact') this.devices.push(new MHDryContact(this.log,accessory)); - if (accessory.accessory == 'MHAux') this.devices.push(new MHAux(this.log,accessory)); - if (accessory.accessory == 'MHScenario') this.devices.push(new MHScenario(this.log,accessory)) - if (accessory.accessory == 'MHPowerMeter') this.devices.push(new MHPowerMeter(this.log,accessory)); - if (accessory.accessory == 'MHAlarm') this.devices.push(new MHAlarm(this.log,accessory)); - if (accessory.accessory == 'MHControlledLoad') this.devices.push(new MHControlledLoad(this.log,accessory)); - if (accessory.accessory == 'MHIrrigation') this.devices.push(new MHIrrigation(this.log,accessory)); - + if (accessory.accessory == 'MHRelay') this.devices.push(new MHRelay(this.log, accessory)); + if (accessory.accessory == 'MHBlind') this.devices.push(new MHBlind(this.log, accessory)); + if (accessory.accessory == 'MHBlindAdvanced') this.devices.push(new MHBlindAdvanced(this.log, accessory)); + if (accessory.accessory == 'MHOutlet') this.devices.push(new MHRelay(this.log, accessory)); + if (accessory.accessory == 'MHTimedRelay') this.devices.push(new MHTimedRelay(this.log, accessory)); + if (accessory.accessory == 'MHRain') this.devices.push(new MHRain(this.log, accessory)); + if (accessory.accessory == 'MHDimmer') this.devices.push(new MHDimmer(this.log, accessory)); + if (accessory.accessory == 'MHThermostat') this.devices.push(new MHThermostat(this.log, accessory)); + if (accessory.accessory == 'MHExternalThermometer') this.devices.push(new MHThermometer(this.log, accessory)); + if (accessory.accessory == 'MHDryContact') this.devices.push(new MHDryContact(this.log, accessory)); + if (accessory.accessory == 'MHAux') this.devices.push(new MHAux(this.log, accessory)); + if (accessory.accessory == 'MHScenario') this.devices.push(new MHScenario(this.log, accessory)); + if (accessory.accessory == 'MHPowerMeter') this.devices.push(new MHPowerMeter(this.log, accessory)); + if (accessory.accessory == 'MHAlarm') this.devices.push(new MHAlarm(this.log, accessory)); + if (accessory.accessory == 'MHControlledLoad') this.devices.push(new MHControlledLoad(this.log, accessory)); + if (accessory.accessory == 'MHIrrigation') this.devices.push(new MHIrrigation(this.log, accessory)); + }.bind(this)); this.log.info("LegrandMyHome for MyHome Gateway at " + config.ipaddress + ":" + config.port); this.controller.start(); @@ -217,14 +217,14 @@ class LegrandMyHome { }.bind(this)); } - onRelay(_address,_onoff) { + onRelay(_address, _onoff) { - var address = _address.split("/"); - if (address.length != 3) return ""; - var a = parseInt(address[1]), pl = parseInt(address[2]); + var address = _address.split("/"); + if (address.length != 3) return ""; + var a = parseInt(address[1]), pl = parseInt(address[2]); - if (pl!=0) - this.devices.forEach(function(accessory) { + if (pl != 0) + this.devices.forEach(function (accessory) { if (accessory.address == _address && accessory.lightBulbService !== undefined) { accessory.power = _onoff; accessory.bri = _onoff * 100; @@ -245,8 +245,8 @@ class LegrandMyHome { } }.bind(this)); else - if (a==0) - this.devices.forEach(function(accessory) { + if (a == 0) + this.devices.forEach(function (accessory) { if (accessory.lightBulbService !== undefined && accessory.pul == false) { accessory.power = _onoff; accessory.bri = _onoff * 100; @@ -262,7 +262,7 @@ class LegrandMyHome { } }.bind(this)); else - this.devices.forEach(function(accessory) { + this.devices.forEach(function (accessory) { if (accessory.ambient == a && accessory.lightBulbService !== undefined && accessory.pul == false) { accessory.power = _onoff; accessory.bri = _onoff * 100; @@ -279,8 +279,8 @@ class LegrandMyHome { }.bind(this)); } - onContactSensor(_address,_state) { - this.devices.forEach(function(accessory) { + onContactSensor(_address, _state) { + this.devices.forEach(function (accessory) { if (accessory.address == _address && accessory.contactSensorService !== undefined) { accessory.state = _state; accessory.contactSensorService.getCharacteristic(Characteristic.ContactSensorState).getValue(null); @@ -288,8 +288,8 @@ class LegrandMyHome { }.bind(this)); } - onScenario(_address,_state) { - this.devices.forEach(function(accessory) { + onScenario(_address, _state) { + this.devices.forEach(function (accessory) { if (accessory.scenarioService !== undefined && accessory.address == _address) { accessory.state = _state; accessory.scenarioService.getCharacteristic(Characteristic.On).getValue(null); @@ -297,92 +297,89 @@ class LegrandMyHome { }.bind(this)); } - onRelayDuration(_address,_value) { - this.devices.forEach(function(accessory) { + onRelayDuration(_address, _value) { + this.devices.forEach(function (accessory) { if (accessory.address == _address && accessory.IrrigationService !== undefined) { - if (accessory.power) - { + if (accessory.power) { accessory.RemDuration = _value; - accessory.timerHandle = setInterval(function() { - accessory.IrrigationService.setCharacteristic(Characteristic.RemainingDuration,accessory.RemDuration); + accessory.timerHandle = setInterval(function () { + accessory.IrrigationService.setCharacteristic(Characteristic.RemainingDuration, accessory.RemDuration); accessory.RemDuration--; if (accessory.RemDuration == 0) clearInterval(accessory.timerHandle); - }.bind(this),1000); + }.bind(this), 1000); } - + } }.bind(this)); } - - - onDryContact(_address,_state) { - this.devices.forEach(function(accessory) { + + + onDryContact(_address, _state) { + this.devices.forEach(function (accessory) { if (accessory.address == _address && accessory.dryContactService !== undefined) { - - switch (accessory.type) { - case 'Contact': - accessory.state = _state; - accessory.dryContactService.getCharacteristic(Characteristic.ContactSensorState).getValue(null); - break; - case 'Leak': - accessory.state = _state; accessory.dryContactService.getCharacteristic(Characteristic.LeakDetected).getValue(null); - break; - case 'Motion': - if (_state==true) - { - accessory.state = true; - accessory.dryContactService.getCharacteristic(Characteristic.MotionDetected).getValue(null); - clearTimeout(accessory.durationhandle); - accessory.durationhandle = setTimeout(function() { - accessory.state = false; - accessory.dryContactService.getCharacteristic(Characteristic.MotionDetected).getValue(null); - }.bind(this), accessory.duration * 1000); - } - else - if (accessory.firstGet == true) - { - accessory.state = _state; + + switch (accessory.type) { + case 'Contact': + accessory.state = _state; + accessory.dryContactService.getCharacteristic(Characteristic.ContactSensorState).getValue(null); + break; + case 'Leak': + accessory.state = _state; accessory.dryContactService.getCharacteristic(Characteristic.LeakDetected).getValue(null); + break; + case 'Motion': + if (_state == true) { + accessory.state = true; accessory.dryContactService.getCharacteristic(Characteristic.MotionDetected).getValue(null); + clearTimeout(accessory.durationhandle); + accessory.durationhandle = setTimeout(function () { + accessory.state = false; + accessory.dryContactService.getCharacteristic(Characteristic.MotionDetected).getValue(null); + }.bind(this), accessory.duration * 1000); } - break; - default: - accessory.state = _state; - accessory.dryContactService.getCharacteristic(Characteristic.ContactSensorState).getValue(null); - break; - } + else + if (accessory.firstGet == true) { + accessory.state = _state; + accessory.dryContactService.getCharacteristic(Characteristic.MotionDetected).getValue(null); + } + break; + default: + accessory.state = _state; + accessory.dryContactService.getCharacteristic(Characteristic.ContactSensorState).getValue(null); + break; + } } }.bind(this)); } - - onAUX(_address,_state) { - this.devices.forEach(function(accessory) { + + onAUX(_address, _state) { + this.devices.forEach(function (accessory) { if (accessory.address == _address && accessory.AUXService !== undefined) { accessory.state = _state; - switch (accessory.type) { - case 'Contact': accessory.AUXService.getCharacteristic(Characteristic.ContactSensorState).getValue(null); - break; - case 'Leak': accessory.AUXService.getCharacteristic(Characteristic.LeakDetected).getValue(null); - break; - case 'Motion': accessory.AUXService.getCharacteristic(Characteristic.MotionDetected).getValue(null); - break; - case 'Gas': accessory.AUXService.getCharacteristic(Characteristic.CarbonMonoxideDetected).getValue(null); - break; - default: accessory.AUXService.getCharacteristic(Characteristic.ContactSensorState).getValue(null); - break; - } + switch (accessory.type) { + case 'Contact': accessory.AUXService.getCharacteristic(Characteristic.ContactSensorState).getValue(null); + break; + case 'Leak': accessory.AUXService.getCharacteristic(Characteristic.LeakDetected).getValue(null); + break; + case 'Motion': accessory.AUXService.getCharacteristic(Characteristic.MotionDetected).getValue(null); + break; + case 'Gas': accessory.AUXService.getCharacteristic(Characteristic.CarbonMonoxideDetected).getValue(null); + break; + default: accessory.AUXService.getCharacteristic(Characteristic.ContactSensorState).getValue(null); + break; + } } }.bind(this)); } - onDimmer(_address,_level) { - var address = _address.split("/"); - if (address.length != 3) return ""; - var a = parseInt(address[1]), pl = parseInt(address[2]); - - if (pl!=0) - this.devices.forEach(function(accessory) { + onDimmer(_address, _level) { + var address = _address.split("/"); + if (address.length != 3) return ""; + var a = parseInt(address[1]), pl = parseInt(address[2]); + + if (pl != 0) + this.devices.forEach(function (accessory) { if (accessory.address == _address && accessory.lightBulbService !== undefined) { accessory.power = (_level > 0) ? 1 : 0; accessory.bri = _level; @@ -391,8 +388,8 @@ class LegrandMyHome { } }.bind(this)); else - if (a==0) - this.devices.forEach(function(accessory) { + if (a == 0) + this.devices.forEach(function (accessory) { if (accessory.lightBulbService !== undefined && accessory.pul == false) { accessory.power = (_level > 0) ? 1 : 0; accessory.bri = _level; @@ -401,7 +398,7 @@ class LegrandMyHome { } }.bind(this)); else - this.devices.forEach(function(accessory) { + this.devices.forEach(function (accessory) { if (accessory.ambient == a && accessory.lightBulbService !== undefined && accessory.pul == false) { accessory.power = (_level > 0) ? 1 : 0; accessory.bri = _level; @@ -412,39 +409,35 @@ class LegrandMyHome { } onPowerMeter(_value) { - this.devices.forEach(function(accessory) { + this.devices.forEach(function (accessory) { if (accessory.powerMeterService !== undefined) { - accessory.value = _value; + accessory.value = _value; } }.bind(this)); } onAlarm(_state) { - this.devices.forEach(function(accessory) { + this.devices.forEach(function (accessory) { if (accessory.alarmService !== undefined) { - if (_state==3) - { + if (_state == 3) { accessory.active = false; accessory.triggered = false; } else - if (_state==1) + if (_state == 1) accessory.active = true; if (_state == 4) accessory.triggered = true; - if ((accessory.active==true && _state!=1)) - { - accessory.state = _state; + if ((accessory.active == true && _state != 1)) { + accessory.state = _state; accessory.alarmService.getCharacteristic(Characteristic.SecuritySystemCurrentState).getValue(null); } - if ((accessory.active==false && _state!=4)) - { - accessory.state = _state; + if ((accessory.active == false && _state != 4)) { + accessory.state = _state; accessory.alarmService.getCharacteristic(Characteristic.SecuritySystemCurrentState).getValue(null); } - - if (_state != 4) - { + + if (_state != 4) { accessory.target = _state; accessory.alarmService.getCharacteristic(Characteristic.SecuritySystemTargetState).getValue(null); } @@ -452,20 +445,20 @@ class LegrandMyHome { }.bind(this)); } - onAlarmFault(_state){ - this.devices.forEach(function(accessory) { + onAlarmFault(_state) { + this.devices.forEach(function (accessory) { if (accessory.alarmService !== undefined) { - accessory.fault = _state; + accessory.fault = _state; accessory.alarmService.getCharacteristic(Characteristic.StatusFault).getValue(null); } }.bind(this)); } - onAlarmTampered(_state){ - this.devices.forEach(function(accessory) { + onAlarmTampered(_state) { + this.devices.forEach(function (accessory) { if (accessory.alarmService !== undefined) { - accessory.tampered = _state; + accessory.tampered = _state; accessory.alarmService.getCharacteristic(Characteristic.StatusTampered).getValue(null); } }.bind(this)); @@ -473,61 +466,58 @@ class LegrandMyHome { } onZoneActive(_zone, _state) { - this.devices.forEach(function(accessory) { + this.devices.forEach(function (accessory) { if (accessory.alarmService !== undefined) { - accessory.zone[_zone] = _state; - if (accessory.zone[0] == true && - accessory.zone[1] == true && - accessory.zone[2] == true && - accessory.zone[3] == true && - accessory.zone[4] == false && - accessory.zone[5] == false && - accessory.zone[6] == false && - accessory.zone[7] == false && - accessory.active == true && - accessory.triggered == false) - { + accessory.zone[_zone] = _state; + if (accessory.zone[0] == true && + accessory.zone[1] == true && + accessory.zone[2] == true && + accessory.zone[3] == true && + accessory.zone[4] == false && + accessory.zone[5] == false && + accessory.zone[6] == false && + accessory.zone[7] == false && + accessory.active == true && + accessory.triggered == false) { accessory.state = Characteristic.SecuritySystemCurrentState.AWAY_ARM; accessory.target = Characteristic.SecuritySystemTargetState.AWAY_ARM; accessory.alarmService.getCharacteristic(Characteristic.SecuritySystemCurrentState).getValue(null); accessory.alarmService.getCharacteristic(Characteristic.SecuritySystemTargetState).getValue(null); - } + } else - if (accessory.zone[0] == true && - accessory.zone[1] == false && - accessory.zone[2] == true && - accessory.zone[3] == false && - accessory.zone[4] == false && - accessory.zone[5] == false && - accessory.zone[6] == false && - accessory.zone[7] == false && - accessory.active == true && - accessory.triggered == false) - { + if (accessory.zone[0] == true && + accessory.zone[1] == false && + accessory.zone[2] == true && + accessory.zone[3] == false && + accessory.zone[4] == false && + accessory.zone[5] == false && + accessory.zone[6] == false && + accessory.zone[7] == false && + accessory.active == true && + accessory.triggered == false) { accessory.state = Characteristic.SecuritySystemCurrentState.NIGHT_ARM; accessory.target = Characteristic.SecuritySystemTargetState.NIGHT_ARM; accessory.alarmService.getCharacteristic(Characteristic.SecuritySystemCurrentState).getValue(null); accessory.alarmService.getCharacteristic(Characteristic.SecuritySystemTargetState).getValue(null); - } + } else - if (accessory.active == true && accessory.triggered == false) - { + if (accessory.active == true && accessory.triggered == false) { accessory.state = Characteristic.SecuritySystemCurrentState.STAY_ARM; accessory.target = Characteristic.SecuritySystemTargetState.STAY_ARM; accessory.alarmService.getCharacteristic(Characteristic.SecuritySystemCurrentState).getValue(null); accessory.alarmService.getCharacteristic(Characteristic.SecuritySystemTargetState).getValue(null); - } + } } }.bind(this)); } - onAlarmLowBattery(_state){ - this.devices.forEach(function(accessory) { + onAlarmLowBattery(_state) { + this.devices.forEach(function (accessory) { if (accessory.alarmBatteryService !== undefined) { - accessory.lowbattery = _state; + accessory.lowbattery = _state; accessory.batterycharging = !_state; - if (_state==0) + if (_state == 0) accessory.batterylevel = 100; else accessory.batterylevel = 0; @@ -539,27 +529,25 @@ class LegrandMyHome { } - onControlledLoad(_address,_value){ - this.devices.forEach(function(accessory) { - if (accessory.controlledLoad !== undefined) - { - if (accessory.address == _address) - { - switch (_value){ + onControlledLoad(_address, _value) { + this.devices.forEach(function (accessory) { + if (accessory.controlledLoad !== undefined) { + if (accessory.address == _address) { + switch (_value) { case 0: - accessory.enabled=false; + accessory.enabled = false; accessory.controlledLoad.getCharacteristic(Characteristic.OutletInUse).getValue(null); break; case 1: - accessory.enabled=true; + accessory.enabled = true; accessory.controlledLoad.getCharacteristic(Characteristic.OutletInUse).getValue(null); break; case 2: - accessory.forced=1; + accessory.forced = 1; accessory.controlledLoad.getCharacteristic(Characteristic.Active).getValue(null); break; case 3: - accessory.forced=0; + accessory.forced = 0; accessory.controlledLoad.getCharacteristic(Characteristic.Active).getValue(null); break; } @@ -567,14 +555,14 @@ class LegrandMyHome { } }.bind(this)); } - - onSimpleBlind(_address,_value) { - var address = _address.split("/"); - if (address.length != 3) return ""; - var a = parseInt(address[1]), pl = parseInt(address[2]); - - if (pl!=0) - this.devices.forEach(function(accessory) { + + onSimpleBlind(_address, _value) { + var address = _address.split("/"); + if (address.length != 3) return ""; + var a = parseInt(address[1]), pl = parseInt(address[2]); + + if (pl != 0) + this.devices.forEach(function (accessory) { if (accessory.address == _address && accessory.windowCoveringService !== undefined) { switch (_value) { case 0: @@ -589,7 +577,7 @@ class LegrandMyHome { accessory.evaluatePosition(); break; case 2: - + if (accessory.invert == false) accessory.state = Characteristic.PositionState.DECREASING; else @@ -603,8 +591,8 @@ class LegrandMyHome { } }.bind(this)); else - if (a==0) - this.devices.forEach(function(accessory) { + if (a == 0) + this.devices.forEach(function (accessory) { if (accessory.windowCoveringService !== undefined && accessory.pul == false) { switch (_value) { case 0: @@ -618,7 +606,7 @@ class LegrandMyHome { accessory.state = Characteristic.PositionState.DECREASING; accessory.evaluatePosition(); break; - case 2: + case 2: if (accessory.invert == false) accessory.state = Characteristic.PositionState.DECREASING; else @@ -632,7 +620,7 @@ class LegrandMyHome { } }.bind(this)); else - this.devices.forEach(function(accessory) { + this.devices.forEach(function (accessory) { if (accessory.ambient == a && accessory.windowCoveringService !== undefined && accessory.pul == false) { switch (_value) { case 0: @@ -661,8 +649,8 @@ class LegrandMyHome { }.bind(this)); } - onAdvancedBlind(_address,_action,_position) { - this.devices.forEach(function(accessory) { + onAdvancedBlind(_address, _action, _position) { + this.devices.forEach(function (accessory) { if (accessory.address == _address && accessory.windowCoveringPlusService !== undefined) { if (_action == "STOP") { accessory.currentPosition = accessory.targetPosition = _position; @@ -687,8 +675,8 @@ class LegrandMyHome { }.bind(this)); } - onThermostat(_address,_measure,_level) { - this.devices.forEach(function(accessory) { + onThermostat(_address, _measure, _level) { + this.devices.forEach(function (accessory) { if (accessory.address == _address && accessory.thermostatService !== undefined) { if (_measure == "AMBIENT") { accessory.ambient = _level; @@ -720,24 +708,24 @@ class LegrandMyHome { accessory.thermostatService.getCharacteristic(Characteristic.TargetHeatingCoolingState).getValue(null); } } - }.bind(this)); + }.bind(this)); } - onThermometer(_address,_measure,_level) { - this.devices.forEach(function(accessory) { + onThermometer(_address, _measure, _level) { + this.devices.forEach(function (accessory) { if (accessory.address == _address && accessory.thermometerService !== undefined) { if (_measure == "AMBIENT") { accessory.ambient = _level; accessory.thermometerService.getCharacteristic(Characteristic.CurrentTemperature).getValue(null); } } - }.bind(this)); - } + }.bind(this)); + } accessories(callback) { this.log.debug("LegrandMyHome (accessories readed)"); callback(this.devices); - } + } } class MHRelay { @@ -747,9 +735,9 @@ class MHRelay { this.name = config.name; this.address = config.address; this.groups = config.groups || []; /* TODO */ - this.pul = config.pul || false; + this.pul = config.pul || false; this.displayName = config.name; - this.UUID = UUIDGen.generate(sprintf("relay-%s",config.address)); + this.UUID = UUIDGen.generate(sprintf("relay-%s", config.address)); this.log = log; this.power = false; this.bri = 100; @@ -758,8 +746,8 @@ class MHRelay { this.log.info(sprintf("LegrandMyHome::MHRelay create object: %s", this.address)); this.mh.addLightBusDevice(this.address); - var address = this.address.split("/"); - this.bus = parseInt(address[0]); + var address = this.address.split("/"); + this.bus = parseInt(address[0]); this.ambient = parseInt(address[1]); this.pl = parseInt(address[2]); } @@ -781,10 +769,10 @@ class MHRelay { break; } - + this.lightBulbService.getCharacteristic(Characteristic.On) .on('set', (level, callback) => { - this.log.debug(sprintf("setPower %s = %s",this.address, level)); + this.log.debug(sprintf("setPower %s = %s", this.address, level)); this.power = (level > 0); if (this.power && this.bri == 0) { this.bri = 100; @@ -796,15 +784,15 @@ class MHRelay { } else if (!this.power && this.config.frame_off != null) { this.mh.send(this.config.frame_off); } else { - this.mh.relayCommand(this.address,this.power); + this.mh.relayCommand(this.address, this.power); } callback(null); }) .on('get', (callback) => { - this.log.debug(sprintf("getPower %s = %s",this.address, this.power)); + this.log.debug(sprintf("getPower %s = %s", this.address, this.power)); callback(null, this.power); }); - + return [service, this.lightBulbService]; } } @@ -816,17 +804,17 @@ class MHTimedRelay { this.name = config.name; this.address = config.address; this.groups = config.groups || []; /* TODO */ - this.pul = config.pul || false; + this.pul = config.pul || false; this.displayName = config.name; - this.UUID = UUIDGen.generate(sprintf("timedrelay-%s",config.address)); + this.UUID = UUIDGen.generate(sprintf("timedrelay-%s", config.address)); this.log = log; this.power = false; this.timer = config.timer || 1; this.log.info(sprintf("LegrandMyHome::MHTimedRelay create object: %s", this.address)); this.mh.addLightBusDevice(this.address); - var address = this.address.split("/"); - this.bus = parseInt(address[0]); + var address = this.address.split("/"); + this.bus = parseInt(address[0]); this.ambient = parseInt(address[1]); this.pl = parseInt(address[2]); } @@ -839,36 +827,34 @@ class MHTimedRelay { .setCharacteristic(Characteristic.FirmwareRevision, version) .setCharacteristic(Characteristic.SerialNumber, "Address " + this.address); - + this.OutletService = new Service.Outlet(this.name); this.OutletService.addCharacteristic(Characteristic.LockManagementAutoSecurityTimeout); this.OutletService.getCharacteristic(Characteristic.LockManagementAutoSecurityTimeout) - .setProps({ - format: Characteristic.Formats.UINT32, - unit: Characteristic.Units.SECONDS, - maxValue: 3540, - minValue: 0, - minStep: 60, - perms: [Characteristic.Perms.READ, Characteristic.Perms.WRITE, Characteristic.Perms.NOTIFY] - }); + .setProps({ + format: Characteristic.Formats.UINT32, + unit: Characteristic.Units.SECONDS, + maxValue: 3540, + minValue: 0, + minStep: 60, + perms: [Characteristic.Perms.READ, Characteristic.Perms.WRITE, Characteristic.Perms.NOTIFY] + }); this.OutletService.getCharacteristic(Characteristic.On) .on('set', (_value, callback) => { //this.log.debug(sprintf("setPower %s = %s",this.address, level)); this.power = _value; - + /* Custom frame support */ - if (this.power && this.timer !=0) - { - this.mh.relayTimedOn(this.address,this.timer/3600,this.timer/60,this.timer%60); + if (this.power && this.timer != 0) { + this.mh.relayTimedOn(this.address, this.timer / 3600, this.timer / 60, this.timer % 60); } - else - { - this.mh.relayCommand(this.address,this.power); + else { + this.mh.relayCommand(this.address, this.power); } callback(null); }) .on('get', (callback) => { - this.log.debug(sprintf("getPower %s = %s",this.address, this.power)); + this.log.debug(sprintf("getPower %s = %s", this.address, this.power)); callback(null, this.power); }); this.OutletService.getCharacteristic(Characteristic.LockManagementAutoSecurityTimeout) @@ -877,11 +863,11 @@ class MHTimedRelay { callback(null); }) .on('get', (callback) => { - this.log.debug(sprintf("getPower %s = %s",this.address, this.power)); + this.log.debug(sprintf("getPower %s = %s", this.address, this.power)); callback(null, this.timer); }); - - + + return [service, this.OutletService]; } } @@ -893,16 +879,16 @@ class MHRain { this.name = config.name; this.address = config.address; this.groups = config.groups || []; /* TODO */ - this.pul = config.pul || false; + this.pul = config.pul || false; this.displayName = config.name; - this.UUID = UUIDGen.generate(sprintf("relay-%s",config.address)); + this.UUID = UUIDGen.generate(sprintf("relay-%s", config.address)); this.log = log; this.power = 0; this.log.info(sprintf("LegrandMyHome::MHRain create object: %s", this.address)); this.mh.addLightBusDevice(this.address); - var address = this.address.split("/"); - this.bus = parseInt(address[0]); + var address = this.address.split("/"); + this.bus = parseInt(address[0]); this.ambient = parseInt(address[1]); this.pl = parseInt(address[2]); } @@ -915,14 +901,14 @@ class MHRain { .setCharacteristic(Characteristic.FirmwareRevision, version) .setCharacteristic(Characteristic.SerialNumber, "Address " + this.address); - + this.rainService = new LegrandMyHome.RainSensorService(this.name); this.rainService.getCharacteristic(Characteristic.CurrentRelativeHumidity) .on('get', (callback) => { //this.log.debug(sprintf("getPower %s = %s",this.address, this.power)); callback(null, 100 - this.power * 100); }); - + return [service, this.rainService]; } } @@ -934,13 +920,13 @@ class MHBlind { this.name = config.name; this.address = config.address; this.groups = config.groups || []; /* TODO */ - this.pul = config.pul || false; + this.pul = config.pul || false; this.displayName = config.name; this.time = config.time || 0; - this.UUID = UUIDGen.generate(sprintf("blind-%s",config.address)); + this.UUID = UUIDGen.generate(sprintf("blind-%s", config.address)); this.log = log; this.invert = config.invert || false; - + this.runningStartTime = -1; this.runningDirection = Characteristic.PositionState.STOPPED; this.state = Characteristic.PositionState.STOPPED; @@ -950,8 +936,8 @@ class MHBlind { this.timeAdjust = config.timeAdjust || 5; /* Percent error, F411 is a bit buggy */ this.log.info(sprintf("LegrandMyHome::MHBlind create object: %s", this.address)); - var address = this.address.split("/"); - this.bus = parseInt(address[0]); + var address = this.address.split("/"); + this.bus = parseInt(address[0]); this.ambient = parseInt(address[1]); this.pl = parseInt(address[2]); } @@ -963,10 +949,10 @@ class MHBlind { this.log.debug(sprintf("Starting position is %d", this.currentPosition)); } else { if (this.runningDirection != Characteristic.PositionState.STOPPED && this.state == Characteristic.PositionState.STOPPED) { - if (this.runningDirection == Characteristic.PositionState.INCREASING) { - this.currentPosition = Math.min(100,this.currentPosition + (100 / (this.time*1000) * (((new Date())-this.runningStartTime+this.startDelayMs)*(1+this.timeAdjust/100)))); + if (this.runningDirection == Characteristic.PositionState.INCREASING) { + this.currentPosition = Math.min(100, this.currentPosition + (100 / (this.time * 1000) * (((new Date()) - this.runningStartTime + this.startDelayMs) * (1 + this.timeAdjust / 100)))); } else { - this.currentPosition = Math.max(0,this.currentPosition - (100 / (this.time*1000) * (((new Date())-this.runningStartTime+this.startDelayMs)*(1+this.timeAdjust/100)))); + this.currentPosition = Math.max(0, this.currentPosition - (100 / (this.time * 1000) * (((new Date()) - this.runningStartTime + this.startDelayMs) * (1 + this.timeAdjust / 100)))); } this.runningDirection = this.state; this.targetPosition = this.currentPosition; @@ -980,9 +966,9 @@ class MHBlind { } /* Calc the needed time to go from Max to Min */ - evaluateTravelTimeMs(from,to) { + evaluateTravelTimeMs(from, to) { if (this.time == 0) return -1; - return ((this.time*1000) / 100 * Math.abs(from-to)); + return ((this.time * 1000) / 100 * Math.abs(from - to)); } getServices() { @@ -997,38 +983,38 @@ class MHBlind { this.windowCoveringService.getCharacteristic(Characteristic.PositionState) .on('get', (callback) => { - this.log.debug(sprintf("getPositionState %s = %s",this.address, this.state)); + this.log.debug(sprintf("getPositionState %s = %s", this.address, this.state)); callback(null, this.state); }); this.windowCoveringService.getCharacteristic(Characteristic.CurrentPosition) .on('get', (callback) => { - this.log.debug(sprintf("getCurrentPosition %s = %s",this.address, this.state)); + this.log.debug(sprintf("getCurrentPosition %s = %s", this.address, this.state)); callback(null, this.currentPosition); - }); + }); this.windowCoveringService.getCharacteristic(Characteristic.TargetPosition) .on('set', (value, callback) => { this.targetPosition = value; - var travelTimeMs = this.evaluateTravelTimeMs(this.currentPosition,this.targetPosition); + var travelTimeMs = this.evaluateTravelTimeMs(this.currentPosition, this.targetPosition); if (value > this.currentPosition) { - this.mh.simpleBlindCommand(this.address,1); + this.mh.simpleBlindCommand(this.address, 1); } else { - this.mh.simpleBlindCommand(this.address,2); + this.mh.simpleBlindCommand(this.address, 2); } /* Use the calculated travel time only if the target isn't the complete Up or Complete Down */ if (this.targetPosition > 0 && this.targetPosition < 100) { if (travelTimeMs > 0) { - setTimeout(function() { - this.mh.simpleBlindCommand(this.address,0); + setTimeout(function () { + this.mh.simpleBlindCommand(this.address, 0); }.bind(this), travelTimeMs); } } callback(null); }) .on('get', (callback) => { - this.log.debug(sprintf("getTargetPosition %s = %s",this.address, this.state)); + this.log.debug(sprintf("getTargetPosition %s = %s", this.address, this.state)); callback(null, this.targetPosition); }); @@ -1046,9 +1032,9 @@ class MHBlindAdvanced { this.pul = false; /* TODO */ this.displayName = config.name; //this.time = config.time || 0; - this.UUID = UUIDGen.generate(sprintf("blindplus-%s",config.address)); + this.UUID = UUIDGen.generate(sprintf("blindplus-%s", config.address)); this.log = log; - + this.state = Characteristic.PositionState.STOPPED; this.currentPosition = 0; this.targetPosition = 0; @@ -1067,13 +1053,13 @@ class MHBlindAdvanced { this.windowCoveringPlusService.getCharacteristic(Characteristic.PositionState) .on('get', (callback) => { - this.log.debug(sprintf("getPositionState %s = %s",this.address, this.state)); + this.log.debug(sprintf("getPositionState %s = %s", this.address, this.state)); callback(null, this.state); }); this.windowCoveringPlusService.getCharacteristic(Characteristic.CurrentPosition) .on('get', (callback) => { - this.log.debug(sprintf("getCurrentPosition %s = %s",this.address, this.state)); + this.log.debug(sprintf("getCurrentPosition %s = %s", this.address, this.state)); callback(null, this.currentPosition); }); @@ -1087,12 +1073,12 @@ class MHBlindAdvanced { } else { this.state = Characteristic.PositionState.DECREASING; } - this.mh.advancedBlindCommand(this.address,this.targetPosition); + this.mh.advancedBlindCommand(this.address, this.targetPosition); this.windowCoveringPlusService.getCharacteristic(Characteristic.PositionState).getValue(null); callback(null); }) .on('get', (callback) => { - this.log.debug(sprintf("getTargetPosition %s = %s",this.address, this.targetPosition)); + this.log.debug(sprintf("getTargetPosition %s = %s", this.address, this.targetPosition)); callback(null, this.targetPosition); }); @@ -1107,19 +1093,19 @@ class MHDimmer { this.name = config.name; this.address = config.address; this.groups = config.groups || []; /* TODO */ - this.pul = config.pul || false; + this.pul = config.pul || false; this.displayName = config.name; - this.UUID = UUIDGen.generate(sprintf("dimmer-%s",config.address)); + this.UUID = UUIDGen.generate(sprintf("dimmer-%s", config.address)); this.log = log; - + this.power = false; this.bri = 100; this.sat = 0; this.hue = 0; this.log.info(sprintf("LegrandMyHome::MHRelay create object: %s", this.address)); - var address = this.address.split("/"); - this.bus = parseInt(address[0]); + var address = this.address.split("/"); + this.bus = parseInt(address[0]); this.ambient = parseInt(address[1]); this.pl = parseInt(address[2]); } @@ -1136,31 +1122,31 @@ class MHDimmer { this.lightBulbService.getCharacteristic(Characteristic.On) .on('set', (level, callback) => { - this.log.debug(sprintf("setPower %s = %s",this.address, level)); + this.log.debug(sprintf("setPower %s = %s", this.address, level)); this.power = (level > 0); if (this.power && this.bri == 0) { this.bri = 100; } - this.mh.relayCommand(this.address,this.power); + this.mh.relayCommand(this.address, this.power); callback(null); }) .on('get', (callback) => { - this.log.debug(sprintf("getPower %s = %s",this.address, this.power)); + this.log.debug(sprintf("getPower %s = %s", this.address, this.power)); callback(null, this.power); }); this.lightBulbService.getCharacteristic(Characteristic.Brightness) .on('set', (level, callback) => { - this.log.debug(sprintf("setBrightness %s = %d",this.address, level)); + this.log.debug(sprintf("setBrightness %s = %d", this.address, level)); this.bri = parseInt(level); this.power = (this.bri > 0); - this.mh.dimmerCommand(this.address,this.bri); + this.mh.dimmerCommand(this.address, this.bri); callback(null); }) .on('get', (callback) => { - this.log.debug(sprintf("getBrightness %s = %d",this.address, this.bri)); + this.log.debug(sprintf("getBrightness %s = %d", this.address, this.bri)); callback(null, this.bri); - }); + }); return [service, this.lightBulbService]; } } @@ -1173,9 +1159,9 @@ class MHThermostat { this.name = config.name; this.address = config.address; this.displayName = config.name; - this.UUID = UUIDGen.generate(sprintf("thermostat-%s",config.address)); + this.UUID = UUIDGen.generate(sprintf("thermostat-%s", config.address)); this.log = log; - + this.ambient = 0; this.setpoint = 20; this.mode = -1; @@ -1192,56 +1178,56 @@ class MHThermostat { .setCharacteristic(Characteristic.SerialNumber, "Address " + this.address); this.thermostatService = new Service.Thermostat(this.name); - this.thermostatService.getCharacteristic(Characteristic.CurrentTemperature).setProps({minValue: -50, minStep: 0.1, maxValue: 50}) + this.thermostatService.getCharacteristic(Characteristic.CurrentTemperature).setProps({ minValue: -50, minStep: 0.1, maxValue: 50 }) .on('get', (callback) => { - this.log.debug(sprintf("getCurrentTemperature %s = %s",this.address, this.ambient)); + this.log.debug(sprintf("getCurrentTemperature %s = %s", this.address, this.ambient)); callback(null, this.ambient); }); this.thermostatService.getCharacteristic(Characteristic.CurrentHeatingCoolingState) .on('get', (callback) => { - this.log.debug(sprintf("getCurrentHeatingCoolingState %s = %s",this.address, this.state)); + this.log.debug(sprintf("getCurrentHeatingCoolingState %s = %s", this.address, this.state)); callback(null, this.state); - }).on('set', (value,callback) => { + }).on('set', (value, callback) => { callback(null); - }); + }); this.thermostatService.getCharacteristic(Characteristic.TargetHeatingCoolingState) .on('get', (callback) => { - this.log.debug(sprintf("getTargetHeatingCoolingState %s = %s",this.address, this.state)); - if (parseInt(this.setpoint,10) > parseInt(this.ambient,10)) { + this.log.debug(sprintf("getTargetHeatingCoolingState %s = %s", this.address, this.state)); + if (parseInt(this.setpoint, 10) > parseInt(this.ambient, 10)) { callback(null, Characteristic.TargetHeatingCoolingState.HEAT); - } else if (parseInt(this.setpoint,10) < parseInt(this.ambient,10)) { + } else if (parseInt(this.setpoint, 10) < parseInt(this.ambient, 10)) { callback(null, Characteristic.TargetHeatingCoolingState.COOL); } else { callback(null, Characteristic.TargetHeatingCoolingState.OFF); } - }).on('set', (value,callback) => { + }).on('set', (value, callback) => { this.state = value; - this.log.debug(sprintf("setTargetHeatingCoolingState %s = %s",this.address, this.state)); + this.log.debug(sprintf("setTargetHeatingCoolingState %s = %s", this.address, this.state)); callback(null); - }); + }); - this.thermostatService.getCharacteristic(Characteristic.TargetTemperature).setProps({minValue: 15, minStep:0.5, maxValue: 40}) + this.thermostatService.getCharacteristic(Characteristic.TargetTemperature).setProps({ minValue: 15, minStep: 0.5, maxValue: 40 }) .on('set', (value, callback) => { - this.log.debug(sprintf("setCurrentSetpoint %s = %s",this.address, value)); - this.mh.setSetPoint(this.address,value); + this.log.debug(sprintf("setCurrentSetpoint %s = %s", this.address, value)); + this.mh.setSetPoint(this.address, value); callback(null); }).on('get', (callback) => { - this.log.debug(sprintf("getCurrentSetpoint %s = %s",this.address, this.setpoint)); + this.log.debug(sprintf("getCurrentSetpoint %s = %s", this.address, this.setpoint)); callback(null, this.setpoint); }); this.thermostatService.getCharacteristic(Characteristic.TemperatureDisplayUnits) - .on('set', (value,callback) => { + .on('set', (value, callback) => { callback(null); }).on('get', (callback) => { - this.log.debug(sprintf("getTemperatureDisplayUnits %s = %s",this.address, this.ambient)); + this.log.debug(sprintf("getTemperatureDisplayUnits %s = %s", this.address, this.ambient)); callback(null, Characteristic.TemperatureDisplayUnits.CELSIUS); }); return [service, this.thermostatService]; - } + } } class MHThermometer { @@ -1251,9 +1237,9 @@ class MHThermometer { this.name = config.name; this.address = config.address; this.displayName = config.name; - this.UUID = UUIDGen.generate(sprintf("thermometer-%s",config.address)); + this.UUID = UUIDGen.generate(sprintf("thermometer-%s", config.address)); this.log = log; - + this.ambient = -1; this.log.info(sprintf("LegrandMyHome::MHThermometer create object: %s", this.address)); } @@ -1267,14 +1253,14 @@ class MHThermometer { .setCharacteristic(Characteristic.SerialNumber, "Address " + this.address); this.thermometerService = new Service.TemperatureSensor(this.name); - this.thermometerService.getCharacteristic(Characteristic.CurrentTemperature).setProps({minValue: -50, minStep: 0.1, maxValue: 50}) + this.thermometerService.getCharacteristic(Characteristic.CurrentTemperature).setProps({ minValue: -50, minStep: 0.1, maxValue: 50 }) .on('get', (callback) => { - this.log.debug(sprintf("getCurrentTemperature %s = %s",this.address, this.ambient)); + this.log.debug(sprintf("getCurrentTemperature %s = %s", this.address, this.ambient)); callback(null, this.ambient); }); return [service, this.thermometerService]; - } + } } class MHPowerMeter { @@ -1283,30 +1269,30 @@ class MHPowerMeter { this.mh = config.parent.controller; this.name = config.name; this.displayName = config.name; - this.UUID = UUIDGen.generate(sprintf("powermeter-%s",config.address)); + this.UUID = UUIDGen.generate(sprintf("powermeter-%s", config.address)); this.log = log; this.refresh = config.refresh || 15; this.intPower = 0; this.acquiredSamples = 0; - this.lastReset = 0; + this.lastReset = 0; this.value = 0; this.totalenergy = 0; this.totalenergytemp = 0; this.ExtraPersistedData = {}; this.log.info(sprintf("LegrandMyHome::MHPowerMeter create object")); - correctingInterval.setCorrectingInterval(function(){ + correctingInterval.setCorrectingInterval(function () { if (this.powerLoggingService.isHistoryLoaded()) { this.ExtraPersistedData = this.powerLoggingService.getExtraPersistedData(); - if (this.ExtraPersistedData != undefined ) { + if (this.ExtraPersistedData != undefined) { this.totalenergy = this.ExtraPersistedData.totalenergy + this.totalenergytemp + this.value * this.refresh / 3600 / 1000; - this.powerLoggingService.setExtraPersistedData({totalenergy:this.totalenergy, lastReset:this.ExtraPersistedData.lastReset}); + this.powerLoggingService.setExtraPersistedData({ totalenergy: this.totalenergy, lastReset: this.ExtraPersistedData.lastReset }); } else { this.totalenergy = this.totalenergytemp + this.value * this.refresh / 3600 / 1000; - this.powerLoggingService.setExtraPersistedData({totalenergy:this.totalenergy, lastReset:0}); + this.powerLoggingService.setExtraPersistedData({ totalenergy: this.totalenergy, lastReset: 0 }); } this.totalenergytemp = 0; - + } else { this.totalenergytemp = this.totalenergytemp + this.value * this.refresh / 3600 / 1000; @@ -1314,19 +1300,19 @@ class MHPowerMeter { } this.powerMeterService.getCharacteristic(LegrandMyHome.CurrentPowerConsumption).getValue(null); this.powerMeterService.getCharacteristic(LegrandMyHome.TotalConsumption).getValue(null); - this.powerLoggingService.addEntry({time: moment().unix(), power:this.value}); + this.powerLoggingService.addEntry({ time: moment().unix(), power: this.value }); this.mh.getPower(); }.bind(this), this.refresh * 1000); } identify(callback) { - this.log("Identify requested!"); - callback(); // success - } + this.log("Identify requested!"); + callback(); // success + } getServices() { var service = new Service.AccessoryInformation(); - + service.setCharacteristic(Characteristic.Name, this.name) .setCharacteristic(Characteristic.Manufacturer, "Simone Tisa") .setCharacteristic(Characteristic.Model, "Power Meter") @@ -1336,38 +1322,38 @@ class MHPowerMeter { this.powerMeterService = new LegrandMyHome.PowerMeterService(this.name); this.powerMeterService.getCharacteristic(LegrandMyHome.CurrentPowerConsumption) .on('get', (callback) => { - this.log.debug(sprintf("getConsumptio = %s",this.value)); + this.log.debug(sprintf("getConsumptio = %s", this.value)); callback(null, this.value); }); this.powerMeterService.getCharacteristic(LegrandMyHome.TotalConsumption) .on('get', (callback) => { this.ExtraPersistedData = this.powerLoggingService.getExtraPersistedData(); - if (this.ExtraPersistedData != undefined ) + if (this.ExtraPersistedData != undefined) this.totalenergy = this.ExtraPersistedData.totalenergy; - this.log.debug(sprintf("getConsumptio = %f",this.totalenergy)); + this.log.debug(sprintf("getConsumptio = %f", this.totalenergy)); callback(null, this.totalenergy); }); this.powerMeterService.getCharacteristic(LegrandMyHome.ResetTotal) .on('set', (value, callback) => { this.totalenergy = 0; this.lastReset = value; - this.powerLoggingService.setExtraPersistedData({totalenergy:this.totalenergy,lastReset:this.lastReset}); + this.powerLoggingService.setExtraPersistedData({ totalenergy: this.totalenergy, lastReset: this.lastReset }); callback(null); }) .on('get', (callback) => { this.ExtraPersistedData = this.powerLoggingService.getExtraPersistedData(); - if (this.ExtraPersistedData != undefined ) + if (this.ExtraPersistedData != undefined) this.lastReset = this.ExtraPersistedData.lastReset; callback(null, this.lastReset); - }); + }); if (this.config.storage == 'fs') - this.powerLoggingService = new LegrandMyHome.FakeGatoHistoryService("energy", this,{storage: 'fs'}); + this.powerLoggingService = new LegrandMyHome.FakeGatoHistoryService("energy", this, { storage: 'fs' }); else - this.powerLoggingService = new LegrandMyHome.FakeGatoHistoryService("energy", this,{storage: 'googleDrive', path: 'homebridge'}); - + this.powerLoggingService = new LegrandMyHome.FakeGatoHistoryService("energy", this, { storage: 'googleDrive', path: 'homebridge' }); + return [service, this.powerMeterService, this.powerLoggingService]; - } + } } class MHButton { @@ -1377,9 +1363,9 @@ class MHButton { this.name = config.name; this.address = config.address; this.displayName = config.name; - this.UUID = UUIDGen.generate(sprintf("button-%s",config.address)); + this.UUID = UUIDGen.generate(sprintf("button-%s", config.address)); this.log = log; - + this.value = 0; this.log.info(sprintf("LegrandMyHome::MHButton (CEN/CEN+) create object: %s", this.address)); } @@ -1394,17 +1380,17 @@ class MHButton { this.statelessSwitch = new Service.Switch(this.name); this.statelessSwitch.getCharacteristic(Characteristic.On) - .on('set', (value,callback) => { - this.log.debug(sprintf("setOn %s = %s",this.address, value)); + .on('set', (value, callback) => { + this.log.debug(sprintf("setOn %s = %s", this.address, value)); callback(null); }) .on('get', (callback) => { - this.log.debug(sprintf("getOn %s",this.address)); - callback(null,0); + this.log.debug(sprintf("getOn %s", this.address)); + callback(null, 0); }); return [service, this.statelessSwitch]; - } - + } + } class MHScenario { @@ -1414,9 +1400,9 @@ class MHScenario { this.name = config.name; this.address = config.address; this.displayName = config.name; - this.UUID = UUIDGen.generate(sprintf("scenario-%s",config.address)); + this.UUID = UUIDGen.generate(sprintf("scenario-%s", config.address)); this.log = log; - + this.state = 0; this.log.info(sprintf("LegrandMyHome::MHScenario create object: %s", this.address)); } @@ -1431,19 +1417,19 @@ class MHScenario { this.scenarioService = new Service.Switch(this.name); this.scenarioService.getCharacteristic(Characteristic.On) - .on('set', (value,callback) => { + .on('set', (value, callback) => { this.state = value; - this.mh.enableScenarioCommand(this.address,this.state); - this.log.debug(sprintf("setOn %s = %s",this.address, this.state)); + this.mh.enableScenarioCommand(this.address, this.state); + this.log.debug(sprintf("setOn %s = %s", this.address, this.state)); callback(null); }) .on('get', (callback) => { - this.log.debug(sprintf("getOn %s",this.address)); - callback(null,this.state); + this.log.debug(sprintf("getOn %s", this.address)); + callback(null, this.state); }); return [service, this.scenarioService]; - } - + } + } @@ -1454,7 +1440,7 @@ class MHDryContact { this.name = config.name; this.address = config.address; this.displayName = config.name; - this.UUID = UUIDGen.generate(sprintf("drycontact-%s",config.address)); + this.UUID = UUIDGen.generate(sprintf("drycontact-%s", config.address)); this.log = log; this.type = config.type; this.numberOpened = 0; @@ -1469,9 +1455,9 @@ class MHDryContact { } identify(callback) { - this.log("Identify requested!"); - callback(); // success - } + this.log("Identify requested!"); + callback(); // success + } getServices() { var service = new Service.AccessoryInformation(); @@ -1485,9 +1471,9 @@ class MHDryContact { case 'Contact': this.dryContactService = new Service.ContactSensor(this.name); if (this.config.storage == 'fs') - this.LoggingService = new LegrandMyHome.FakeGatoHistoryService("door", this,{storage: 'fs'}); + this.LoggingService = new LegrandMyHome.FakeGatoHistoryService("door", this, { storage: 'fs' }); else - this.LoggingService = new LegrandMyHome.FakeGatoHistoryService("door", this,{storage: 'googleDrive', path: 'homebridge'}); + this.LoggingService = new LegrandMyHome.FakeGatoHistoryService("door", this, { storage: 'googleDrive', path: 'homebridge' }); this.dryContactService.addCharacteristic(LegrandMyHome.LastActivation); this.dryContactService.addCharacteristic(LegrandMyHome.TimesOpened); this.dryContactService.addCharacteristic(LegrandMyHome.ResetTotal); @@ -1502,55 +1488,55 @@ class MHDryContact { this.dryContactService.getCharacteristic(Characteristic.ContactSensorState) .on('get', (callback) => { - this.log.debug(sprintf("getContactSensorState %s = %s",this.address, this.state)); - if (this.firstGet) { - this.firstGet = false; - this.LoggingService.addEntry({time: moment().unix(), status: this.state}); - } - callback(null, this.state); + this.log.debug(sprintf("getContactSensorState %s = %s", this.address, this.state)); + if (this.firstGet) { + this.firstGet = false; + this.LoggingService.addEntry({ time: moment().unix(), status: this.state }); + } + callback(null, this.state); }); this.dryContactService.getCharacteristic(Characteristic.ContactSensorState) .on('change', () => { - this.log.debug(sprintf("changeContactSensorState %s = %s",this.address, this.state)); - this.lastOpening = moment().unix()-this.LoggingService.getInitialTime(); - if (this.state) { - this.ExtraPersistedData = this.LoggingService.getExtraPersistedData(); - if (this.ExtraPersistedData != undefined && this.ExtraPersistedData.numberOpened != undefined) - this.numberOpened = this.ExtraPersistedData.numberOpened + 1; - else - this.numberOpened++; - } - this.LoggingService.setExtraPersistedData({numberOpened:this.numberOpened, lastOpening: this.lastOpening, lastReset:this.lastReset}); - this.LoggingService.addEntry({time: moment().unix(), status: this.state}); + this.log.debug(sprintf("changeContactSensorState %s = %s", this.address, this.state)); + this.lastOpening = moment().unix() - this.LoggingService.getInitialTime(); + if (this.state) { + this.ExtraPersistedData = this.LoggingService.getExtraPersistedData(); + if (this.ExtraPersistedData != undefined && this.ExtraPersistedData.numberOpened != undefined) + this.numberOpened = this.ExtraPersistedData.numberOpened + 1; + else + this.numberOpened++; + } + this.LoggingService.setExtraPersistedData({ numberOpened: this.numberOpened, lastOpening: this.lastOpening, lastReset: this.lastReset }); + this.LoggingService.addEntry({ time: moment().unix(), status: this.state }); }); this.dryContactService.getCharacteristic(LegrandMyHome.ResetTotal) .on('set', (value, callback) => { this.numberOpened = 0; this.lastReset = value; - this.LoggingService.setExtraPersistedData({numberOpened:this.numberOpened, lastOpening: this.lastOpening, lastReset:this.lastReset}); - this.LoggingService.addEntry({time: moment().unix(), status: this.state}); + this.LoggingService.setExtraPersistedData({ numberOpened: this.numberOpened, lastOpening: this.lastOpening, lastReset: this.lastReset }); + this.LoggingService.addEntry({ time: moment().unix(), status: this.state }); callback(null); }) .on('get', (callback) => { this.ExtraPersistedData = this.LoggingService.getExtraPersistedData(); - if (this.ExtraPersistedData != undefined ) + if (this.ExtraPersistedData != undefined) this.lastReset = this.ExtraPersistedData.lastReset; callback(null, this.lastReset); }); this.dryContactService.getCharacteristic(LegrandMyHome.TimesOpened) .on('get', (callback) => { this.ExtraPersistedData = this.LoggingService.getExtraPersistedData(); - if (this.ExtraPersistedData != undefined ) + if (this.ExtraPersistedData != undefined) this.numberOpened = this.ExtraPersistedData.numberOpened; - this.log.debug(sprintf("getNumberOpened = %f",this.numberOpened)); + this.log.debug(sprintf("getNumberOpened = %f", this.numberOpened)); callback(null, this.numberOpened); }); this.dryContactService.getCharacteristic(LegrandMyHome.LastActivation) .on('get', (callback) => { this.ExtraPersistedData = this.LoggingService.getExtraPersistedData(); - if (this.ExtraPersistedData != undefined ) + if (this.ExtraPersistedData != undefined) this.lastOpening = this.ExtraPersistedData.lastOpening; - this.log.debug(sprintf("lastOpening = %f",this.lastOpening)); + this.log.debug(sprintf("lastOpening = %f", this.lastOpening)); callback(null, this.lastOpening); }); return [service, this.dryContactService, this.LoggingService]; @@ -1558,40 +1544,40 @@ class MHDryContact { this.dryContactService = new Service.LeakSensor(this.name); this.dryContactService.getCharacteristic(Characteristic.LeakDetected) .on('get', (callback) => { - this.log.debug(sprintf("getLeakSensorState %s = %s",this.address, this.state)); - callback(null, this.state); - }); + this.log.debug(sprintf("getLeakSensorState %s = %s", this.address, this.state)); + callback(null, this.state); + }); return [service, this.dryContactService]; case 'Motion': this.dryContactService = new Service.MotionSensor(this.name); if (this.config.storage == 'fs') - this.LoggingService = new LegrandMyHome.FakeGatoHistoryService("motion", this,{storage: 'fs'}); + this.LoggingService = new LegrandMyHome.FakeGatoHistoryService("motion", this, { storage: 'fs' }); else - this.LoggingService = new LegrandMyHome.FakeGatoHistoryService("motion", this,{storage: 'googleDrive', path: 'homebridge'}); + this.LoggingService = new LegrandMyHome.FakeGatoHistoryService("motion", this, { storage: 'googleDrive', path: 'homebridge' }); this.dryContactService.addCharacteristic(LegrandMyHome.Sensitivity); this.dryContactService.addCharacteristic(LegrandMyHome.Duration); - this.dryContactService.addCharacteristic(LegrandMyHome.LastActivation); - this.dryContactService.setCharacteristic(LegrandMyHome.Duration,this.duration); + this.dryContactService.addCharacteristic(LegrandMyHome.LastActivation); + this.dryContactService.setCharacteristic(LegrandMyHome.Duration, this.duration); this.ExtraPersistedData = this.LoggingService.getExtraPersistedData(); if (this.ExtraPersistedData != undefined) { this.lastActivation = this.ExtraPersistedData.lastActivation || 0; - } + } this.dryContactService.getCharacteristic(Characteristic.MotionDetected) .on('get', (callback) => { - this.log.debug(sprintf("getMotionSensorState %s = %s",this.address, this.state)); - if (this.firstGet) { - this.firstGet = false; - this.LoggingService.addEntry({time: moment().unix(), status: this.state}); - } - callback(null, this.state); - }); + this.log.debug(sprintf("getMotionSensorState %s = %s", this.address, this.state)); + if (this.firstGet) { + this.firstGet = false; + this.LoggingService.addEntry({ time: moment().unix(), status: this.state }); + } + callback(null, this.state); + }); this.dryContactService.getCharacteristic(Characteristic.MotionDetected) .on('change', () => { - this.log.debug(sprintf("changeMotionSensorState %s = %s",this.address, this.state)); - this.lastActivation = moment().unix()-this.LoggingService.getInitialTime(); - this.LoggingService.setExtraPersistedData({lastActivation: this.lastActivation}); - this.LoggingService.addEntry({time: moment().unix(), status: this.state}); - + this.log.debug(sprintf("changeMotionSensorState %s = %s", this.address, this.state)); + this.lastActivation = moment().unix() - this.LoggingService.getInitialTime(); + this.LoggingService.setExtraPersistedData({ lastActivation: this.lastActivation }); + this.LoggingService.addEntry({ time: moment().unix(), status: this.state }); + }); this.dryContactService.getCharacteristic(LegrandMyHome.Duration) .on('set', (value, callback) => { @@ -1604,25 +1590,25 @@ class MHDryContact { this.dryContactService.getCharacteristic(LegrandMyHome.LastActivation) .on('get', (callback) => { this.ExtraPersistedData = this.LoggingService.getExtraPersistedData(); - if (this.ExtraPersistedData != undefined ) + if (this.ExtraPersistedData != undefined) this.lastActivation = this.ExtraPersistedData.lastActivation; - this.log.debug(sprintf("lastActivation = %f",this.lastActivation)); + this.log.debug(sprintf("lastActivation = %f", this.lastActivation)); callback(null, this.lastActivation); }); - + return [service, this.dryContactService, this.LoggingService]; default: this.dryContactService = new Service.ContactSensor(this.name); this.dryContactService.getCharacteristic(Characteristic.ContactSensorState) .on('get', (callback) => { - this.log.debug(sprintf("getContactSensorState %s = %s",this.address, this.state)); - callback(null, this.state); + this.log.debug(sprintf("getContactSensorState %s = %s", this.address, this.state)); + callback(null, this.state); }); return [service, this.dryContactService]; } - - } + + } } class MHAux { @@ -1632,10 +1618,10 @@ class MHAux { this.name = config.name; this.address = config.address; this.displayName = config.name; - this.UUID = UUIDGen.generate(sprintf("aux-%s",config.address)); + this.UUID = UUIDGen.generate(sprintf("aux-%s", config.address)); this.log = log; this.type = config.type; - + this.state = false; this.log.info(sprintf("LegrandMyHome::MHAux create object: %s", this.address)); } @@ -1653,46 +1639,46 @@ class MHAux { this.AUXService = new Service.ContactSensor(this.name); this.AUXService.getCharacteristic(Characteristic.ContactSensorState) .on('get', (callback) => { - this.log.debug(sprintf("getContactSensorState %s = %s",this.address, this.state)); - callback(null, this.state); + this.log.debug(sprintf("getContactSensorState %s = %s", this.address, this.state)); + callback(null, this.state); }); break; case 'Leak': this.AUXService = new Service.LeakSensor(this.name); this.AUXService.getCharacteristic(Characteristic.LeakDetected) .on('get', (callback) => { - this.log.debug(sprintf("getLeakSensorState %s = %s",this.address, this.state)); - callback(null, this.state); - }); + this.log.debug(sprintf("getLeakSensorState %s = %s", this.address, this.state)); + callback(null, this.state); + }); break; case 'Motion': this.AUXService = new Service.MotionSensor(this.name); this.AUXService.getCharacteristic(Characteristic.MotionDetected) .on('get', (callback) => { - this.log.debug(sprintf("getMotionSensorState %s = %s",this.address, this.state)); - callback(null, this.state); - }); + this.log.debug(sprintf("getMotionSensorState %s = %s", this.address, this.state)); + callback(null, this.state); + }); break; case 'Gas': this.AUXService = new Service.CarbonMonoxideSensor(this.name); this.AUXService.getCharacteristic(Characteristic.CarbonMonoxideDetected) .on('get', (callback) => { - this.log.debug(sprintf("getGasSensorState %s = %s",this.address, this.state)); - callback(null, this.state); - }); + this.log.debug(sprintf("getGasSensorState %s = %s", this.address, this.state)); + callback(null, this.state); + }); break; default: this.AUXService = new Service.ContactSensor(this.name); this.AUXService.getCharacteristic(Characteristic.ContactSensorState) .on('get', (callback) => { - this.log.debug(sprintf("getContactSensorState %s = %s",this.address, this.state)); - callback(null, this.state); + this.log.debug(sprintf("getContactSensorState %s = %s", this.address, this.state)); + callback(null, this.state); }); break; } return [service, this.AUXService]; - } + } } class MHAlarm { @@ -1701,9 +1687,9 @@ class MHAlarm { this.mh = config.parent.controller; this.name = config.name; this.displayName = config.name; - this.UUID = UUIDGen.generate(sprintf("alarm-%s",config.address)); + this.UUID = UUIDGen.generate(sprintf("alarm-%s", config.address)); this.log = log; - + this.state = Characteristic.SecuritySystemCurrentState.DISARMED; this.target = Characteristic.SecuritySystemCurrentState.DISARMED; this.fault = Characteristic.StatusFault.NO_FAULT; @@ -1711,12 +1697,12 @@ class MHAlarm { this.lowbattery = Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL; this.batterycharging = Characteristic.ChargingState.NOT_CHARGING; this.batterylevel = 100; - this.zone = [true, true,true,true,false,false,false,false]; + this.zone = [true, true, true, true, false, false, false, false]; this.active = false; this.triggered = false; - + this.log.info(sprintf("LegrandMyHome::MHAlarm create object")); - + } getServices() { @@ -1730,48 +1716,48 @@ class MHAlarm { this.alarmService = new Service.SecuritySystem(this.name); this.alarmService.getCharacteristic(Characteristic.SecuritySystemCurrentState) .on('get', (callback) => { - this.log.debug(sprintf("alarm current = %d",this.state)); + this.log.debug(sprintf("alarm current = %d", this.state)); callback(null, this.state); }); this.alarmService.getCharacteristic(Characteristic.SecuritySystemTargetState) .on('get', (callback) => { - this.log.debug(sprintf("alarm get target = %d",this.target)); + this.log.debug(sprintf("alarm get target = %d", this.target)); callback(null, this.target); }) - .on('set', (value,callback) => { + .on('set', (value, callback) => { this.log.debug(sprintf("alarm set target= %d", this.target)); callback(null); }); this.alarmService.getCharacteristic(Characteristic.StatusFault) .on('get', (callback) => { - this.log.debug(sprintf("getConsumptio = %s",this.value)); + this.log.debug(sprintf("getConsumptio = %s", this.value)); callback(null, this.fault); }); this.alarmService.getCharacteristic(Characteristic.StatusTampered) .on('get', (callback) => { - this.log.debug(sprintf("getConsumptio = %s",this.value)); + this.log.debug(sprintf("getConsumptio = %s", this.value)); callback(null, this.tampered); }); this.alarmBatteryService = new Service.BatteryService(this.name); this.alarmBatteryService.getCharacteristic(Characteristic.StatusLowBattery) .on('get', (callback) => { - this.log.debug(sprintf("alarm current = %d",this.state)); + this.log.debug(sprintf("alarm current = %d", this.state)); callback(null, this.lowbattery); }); this.alarmBatteryService.getCharacteristic(Characteristic.BatteryLevel) .on('get', (callback) => { - this.log.debug(sprintf("alarm current = %d",this.state)); + this.log.debug(sprintf("alarm current = %d", this.state)); callback(null, this.batterylevel); }); this.alarmBatteryService.getCharacteristic(Characteristic.ChargingState) .on('get', (callback) => { - this.log.debug(sprintf("alarm current = %d",this.state)); + this.log.debug(sprintf("alarm current = %d", this.state)); callback(null, this.batterycharging); }); - - + + return [service, this.alarmService, this.alarmBatteryService]; - } + } } class MHControlledLoad { @@ -1781,9 +1767,9 @@ class MHControlledLoad { this.name = config.name; this.address = config.address; this.displayName = config.name; - this.UUID = UUIDGen.generate(sprintf("controlledload-%s",config.address)); + this.UUID = UUIDGen.generate(sprintf("controlledload-%s", config.address)); this.log = log; - + this.enabled = true; this.forced = 0; this.log.info(sprintf("LegrandMyHome::MHControlledLoad create priority: %s", this.address)); @@ -1800,40 +1786,38 @@ class MHControlledLoad { this.controlledLoad = new LegrandMyHome.ControlledLoadService(this.name); this.controlledLoad.getCharacteristic(Characteristic.Active) - .on('set', (value,callback) => { - this.log.debug(sprintf("setOn %s = %s",this.address, value)); - - if (value == 1) - { + .on('set', (value, callback) => { + this.log.debug(sprintf("setOn %s = %s", this.address, value)); + + if (value == 1) { this.enabled = true; this.forced = value; - this.mh.forcedLoadCommand(this.address,this.forced); + this.mh.forcedLoadCommand(this.address, this.forced); callback(null); } - else - { + else { this.forced = 0; this.controlledLoad.getCharacteristic(Characteristic.Active).getValue(null); - setTimeout(function() { + setTimeout(function () { this.forced = 1; this.controlledLoad.getCharacteristic(Characteristic.Active).getValue(null); - }.bind(this),500); + }.bind(this), 500); callback(null); } - + }) .on('get', (callback) => { - this.log.debug(sprintf("getOn %s",this.address)); - callback(null,this.forced); + this.log.debug(sprintf("getOn %s", this.address)); + callback(null, this.forced); }); this.controlledLoad.getCharacteristic(Characteristic.OutletInUse) .on('get', (callback) => { - this.log.debug(sprintf("getOn %s",this.address)); - callback(null,this.enabled); + this.log.debug(sprintf("getOn %s", this.address)); + callback(null, this.enabled); }); return [service, this.controlledLoad]; - } - + } + } class MHIrrigation { @@ -1843,9 +1827,9 @@ class MHIrrigation { this.name = config.name; this.address = config.address; this.groups = config.groups || []; /* TODO */ - this.pul = config.pul || false; + this.pul = config.pul || false; this.displayName = config.name; - this.UUID = UUIDGen.generate(sprintf("irrigation-%s",config.address)); + this.UUID = UUIDGen.generate(sprintf("irrigation-%s", config.address)); this.log = log; this.power = false; this.RemDuration = 1; @@ -1853,8 +1837,8 @@ class MHIrrigation { this.timerHandle = 0; this.log.info(sprintf("LegrandMyHome::MHIrrigation create object: %s", this.address)); this.mh.addLightBusDevice(this.address); - var address = this.address.split("/"); - this.bus = parseInt(address[0]); + var address = this.address.split("/"); + this.bus = parseInt(address[0]); this.ambient = parseInt(address[1]); this.pl = parseInt(address[2]); this.lastActivation = 0; @@ -1875,68 +1859,64 @@ class MHIrrigation { // just to make the irrigation icon show in Eve, real history signature needed this.IrrigationService.addCharacteristic(LegrandMyHome.LastActivation); if (this.config.storage == 'fs') - this.LoggingService = new LegrandMyHome.FakeGatoHistoryService("motion", this,{storage: 'fs', disableTimer: true}); + this.LoggingService = new LegrandMyHome.FakeGatoHistoryService("motion", this, { storage: 'fs', disableTimer: true }); else - this.LoggingService = new LegrandMyHome.FakeGatoHistoryService("motion", this,{storage: 'googleDrive', path: 'homebridge', disableTimer: true}); + this.LoggingService = new LegrandMyHome.FakeGatoHistoryService("motion", this, { storage: 'googleDrive', path: 'homebridge', disableTimer: true }); this.ExtraPersistedData = this.LoggingService.getExtraPersistedData(); if (this.ExtraPersistedData != undefined) { this.lastActivation = this.ExtraPersistedData.lastActivation || 0; - } + } - this.IrrigationService.setCharacteristic(Characteristic.ValveType,1); - this.IrrigationService.setCharacteristic(Characteristic.SetDuration,this.timer); + this.IrrigationService.setCharacteristic(Characteristic.ValveType, 1); + this.IrrigationService.setCharacteristic(Characteristic.SetDuration, this.timer); this.IrrigationService.getCharacteristic(Characteristic.Active) .on('set', (_value, callback) => { - this.log.debug(sprintf("setIrrigation %s = %s",this.address, _value)); + this.log.debug(sprintf("setIrrigation %s = %s", this.address, _value)); this.power = _value; - if (this.power) - { - this.mh.relayTimedOn(this.address,this.timer/3600,this.timer/60,this.timer%60); + if (this.power) { + this.mh.relayTimedOn(this.address, this.timer / 3600, this.timer / 60, this.timer % 60); } - else - { - this.mh.relayCommand(this.address,this.power); + else { + this.mh.relayCommand(this.address, this.power); } callback(null); }) .on('get', (callback) => { - this.log.debug(sprintf("getIrrigation %s = %s",this.address, this.power)); + this.log.debug(sprintf("getIrrigation %s = %s", this.address, this.power)); callback(null, this.power); }); this.IrrigationService.getCharacteristic(Characteristic.InUse) .on('get', (callback) => { if (this.firstGet) { this.firstGet = false; - this.LoggingService.addEntry({time: moment().unix(), status: this.power}); + this.LoggingService.addEntry({ time: moment().unix(), status: this.power }); } callback(null, this.power); }) - .on('change',() => { - if (this.power) - { + .on('change', () => { + if (this.power) { setTimeout(function () { this.mh.getRelayDuration(this.address); - }.bind(this),1000); + }.bind(this), 1000); } - else - { + else { clearInterval(this.timerHandle); this.RemDuration = 0; - this.IrrigationService.setCharacteristic(Characteristic.RemainingDuration,this.RemDuration); - } - this.log.debug(sprintf("changeIrrigation %s = %s",this.address, this.power)); - this.lastActivation = moment().unix()-this.LoggingService.getInitialTime(); - this.LoggingService.setExtraPersistedData({lastActivation: this.lastActivation}); - this.LoggingService.addEntry({time: moment().unix(), status: this.power}); - }); + this.IrrigationService.setCharacteristic(Characteristic.RemainingDuration, this.RemDuration); + } + this.log.debug(sprintf("changeIrrigation %s = %s", this.address, this.power)); + this.lastActivation = moment().unix() - this.LoggingService.getInitialTime(); + this.LoggingService.setExtraPersistedData({ lastActivation: this.lastActivation }); + this.LoggingService.addEntry({ time: moment().unix(), status: this.power }); + }); this.IrrigationService.getCharacteristic(Characteristic.SetDuration) .on('set', (time, callback) => { this.timer = time; callback(null); }) - .on('get', (callback) => { - callback(null, this.timer); + .on('get', (callback) => { + callback(null, this.timer); }); this.IrrigationService.getCharacteristic(Characteristic.RemainingDuration) .on('set', (time, callback) => { @@ -1949,12 +1929,12 @@ class MHIrrigation { this.IrrigationService.getCharacteristic(LegrandMyHome.LastActivation) .on('get', (callback) => { this.ExtraPersistedData = this.LoggingService.getExtraPersistedData(); - if (this.ExtraPersistedData != undefined ) + if (this.ExtraPersistedData != undefined) this.lastActivation = this.ExtraPersistedData.lastActivation; - this.log.debug(sprintf("lastActivation = %f",this.lastActivation)); + this.log.debug(sprintf("lastActivation = %f", this.lastActivation)); callback(null, this.lastActivation); }); - + return [service, this.IrrigationService, this.LoggingService]; } } \ No newline at end of file diff --git a/lib/mhclient.js b/lib/mhclient.js index a7071a8..ead95ca 100755 --- a/lib/mhclient.js +++ b/lib/mhclient.js @@ -9,8 +9,8 @@ const moment = require('moment'); function inArray(needle, haystack) { var length = haystack.length; - for(var i = 0; i < length; i++) { - if(haystack[i] == needle) + for (var i = 0; i < length; i++) { + if (haystack[i] == needle) return true; } return false; @@ -24,7 +24,7 @@ class MyHomeClient { constructor(_ipaddress, _port, _password, _setclock, _classToCallback) { // Ten level translation, 0=0=Off, 1 = 100=On, 2=1%, 3=10%, 4=20%...8=60%,9=75,10=100% - this.dimmerLevels = [0,100,1,10,20,30,40,50,60,75,100]; + this.dimmerLevels = [0, 100, 1, 10, 20, 30, 40, 50, 60, 75, 100]; this.buffers = {}; this.lightBuses = []; this.ipaddress = _ipaddress; @@ -43,11 +43,11 @@ class MyHomeClient { * Fill the this.lightBuses array to know how many bus(es) should be polled at the startup */ addLightBusDevice(_address) { - var address = _address.split("/"); + var address = _address.split("/"); if (address.length != 3) return ""; // Add this bus if it wasn't already in list - if (!inArray(address[0],this.lightBuses)) this.lightBuses.push(address[0]); + if (!inArray(address[0], this.lightBuses)) this.lightBuses.push(address[0]); } send(_command) { @@ -55,34 +55,32 @@ class MyHomeClient { } _slashesToAddress(_address) { - var address = _address.split("/"); + var address = _address.split("/"); if (address.length != 3) return ""; var b = parseInt(address[0]), a = parseInt(address[1]), pl = parseInt(address[2]); - if (b == 0) - { + if (b == 0) { if (a >= 10 || pl >= 10) { - return sprintf("%02d%02d",a,pl); + return sprintf("%02d%02d", a, pl); } else - if (pl==0) - return sprintf("%d",a); + if (pl == 0) + return sprintf("%d", a); else - return sprintf("%d%d",a,pl); - } - else - { + return sprintf("%d%d", a, pl); + } + else { if (a >= 10 || pl >= 10) { - return sprintf("%02d%02d#4#%02d",a,pl,b); + return sprintf("%02d%02d#4#%02d", a, pl, b); } - return sprintf("%d%d#4#%02d",a,pl,b); + return sprintf("%d%d#4#%02d", a, pl, b); } } _addressToSlashes(_address) { - if (_address.length == 4) return sprintf("0/%d/%d", parseInt(_address.substring(0,2)),parseInt(_address.substring(2,4))); - if (_address.length == 2) return sprintf("0/%d/%d", parseInt(_address.substring(0,1)),parseInt(_address.substring(1,2))); + if (_address.length == 4) return sprintf("0/%d/%d", parseInt(_address.substring(0, 2)), parseInt(_address.substring(2, 4))); + if (_address.length == 2) return sprintf("0/%d/%d", parseInt(_address.substring(0, 1)), parseInt(_address.substring(1, 2))); if (_address.length == 1) return sprintf("0/%d/0", parseInt(_address)); // TODO return "9/99/99"; @@ -92,77 +90,76 @@ class MyHomeClient { * Avoid repeated calls of the same command on a short time, it can happen with the dimmer control on iOS * It buffer the commands and sends the last one. */ - _bufferCommand(_class,_address,_command, _timeout) { - if (this.buffers[sprintf("%s-%s",_class,_address)] != null) { - clearTimeout(this.buffers[sprintf("%s-%s",_class,_address)]); + _bufferCommand(_class, _address, _command, _timeout) { + if (this.buffers[sprintf("%s-%s", _class, _address)] != null) { + clearTimeout(this.buffers[sprintf("%s-%s", _class, _address)]); } - this.buffers[sprintf("%s-%s",_class,_address)] = setTimeout(function() { + this.buffers[sprintf("%s-%s", _class, _address)] = setTimeout(function () { this.command.send(_command); - delete(this.buffers[sprintf("%s-%s",_class,_address)]); + delete (this.buffers[sprintf("%s-%s", _class, _address)]); }.bind(this), _timeout); } - relayCommand(_address,_on) { + relayCommand(_address, _on) { var address = this._slashesToAddress(_address); if (address == "") return; - this.command.send(sprintf("*1*%d*%s##",(_on)?1:0,address)); + this.command.send(sprintf("*1*%d*%s##", (_on) ? 1 : 0, address)); } - relayTimedOn(_address,hh,mm,ss) { + relayTimedOn(_address, hh, mm, ss) { var address = this._slashesToAddress(_address); if (address == "") return; this.command.send(sprintf("*#1*%s*#2*%d*%d*%d##", address, hh, mm, ss)); } - simpleBlindCommand(_address,_stopUpDown) { + simpleBlindCommand(_address, _stopUpDown) { var address = this._slashesToAddress(_address); if (address == "") return; /* Send a starting stop */ if (_stopUpDown != 0) { - this.command.send(sprintf("*2*%d*%s##",0,address)); + this.command.send(sprintf("*2*%d*%s##", 0, address)); } - this.command.send(sprintf("*2*%d*%s##",parseInt(_stopUpDown),address)); - } + this.command.send(sprintf("*2*%d*%s##", parseInt(_stopUpDown), address)); + } - advancedBlindCommand(_address,_shutterLevel) { + advancedBlindCommand(_address, _shutterLevel) { var address = this._slashesToAddress(_address); if (address == "") return; - this.command.send(sprintf("*#2*%s*#11#1*%d##",address,parseInt(_shutterLevel))); - } + this.command.send(sprintf("*#2*%s*#11#1*%d##", address, parseInt(_shutterLevel))); + } + + dimmerCommand(_address, _bri) { + // 2013.04.12 - angeloxx - LG explains speed parameter of the *#1**#1** OWN frame + // Speed is the single-step-time in 10ms scale. So the ramp time is: + // time = * 10ms * , where delta is abs(currentlevel-finallevel). + // speed = ( / 10ms) / , delta level is [current|final]level*1000, ramptime is in ms - dimmerCommand(_address,_bri) { - // 2013.04.12 - angeloxx - LG explains speed parameter of the *#1**#1** OWN frame - // Speed is the single-step-time in 10ms scale. So the ramp time is: - // time = * 10ms * , where delta is abs(currentlevel-finallevel). - // speed = ( / 10ms) / , delta level is [current|final]level*1000, ramptime is in ms - var address = this._slashesToAddress(_address); if (address == "") return; if (_bri > 0) { - this._bufferCommand("DIMMER",address,sprintf("*#1*%s*#1*%s*1##",address,_bri+100),500); + this._bufferCommand("DIMMER", address, sprintf("*#1*%s*#1*%s*1##", address, _bri + 100), 500); } else { - this._bufferCommand("DIMMER",address,sprintf("*1*0*%s##",address),500); + this._bufferCommand("DIMMER", address, sprintf("*1*0*%s##", address), 500); } } - - forcedLoadCommand(_address,_forced) - { + + forcedLoadCommand(_address, _forced) { if (_address == "") return; if (_forced == 1) - this.command.send(sprintf("*3*2*#%d##",_address)); + this.command.send(sprintf("*3*2*#%d##", _address)); } - - enableScenarioCommand(_address,_status) { + + enableScenarioCommand(_address, _status) { if (_address == "") return; - this.command.send(sprintf("*17*%d*%s##",(_status)?3:4,_address)); + this.command.send(sprintf("*17*%d*%s##", (_status) ? 3 : 4, _address)); } - setSetPoint(_address,_temperature) { + setSetPoint(_address, _temperature) { // Standard thermostat *4*40*%02d##*#4*#%02d*#14*%04d*3 - this._bufferCommand("THERMO",_address,sprintf("*4*40*%02d##*#4*#%02d*#14*%04d*3##*#4*%02d*14##",_address,_address,_temperature * 10,_address),500); + this._bufferCommand("THERMO", _address, sprintf("*4*40*%02d##*#4*#%02d*#14*%04d*3##*#4*%02d*14##", _address, _address, _temperature * 10, _address), 500); // 4 Zones *#4*#0#%02d*#14*%04d*3 } @@ -171,32 +168,32 @@ class MyHomeClient { * sends a light status request for all known buses */ onCommandConnect() { - this.lightBuses.forEach(function(element) { + this.lightBuses.forEach(function (element) { if (element == 0) { this.command.send("*#1*0##"); } else { - this.command.send(sprintf("*#1*0#4#%02d##",element)); + this.command.send(sprintf("*#1*0#4#%02d##", element)); } }, this); - + //request also AUX states this.command.send("*#9##"); - + //request also controlled load states this.command.send("*#3##"); /* Light status well keep some seconds, so I prefer to wait to send the connect feedback */ - setTimeout(function() { - if (this.parent != null && this.parent.onConnect != null && typeof(this.parent.onConnect) == 'function') this.parent.onConnect(); - }.bind(this),this.lightBuses.length * 2500); + setTimeout(function () { + if (this.parent != null && this.parent.onConnect != null && typeof (this.parent.onConnect) == 'function') this.parent.onConnect(); + }.bind(this), this.lightBuses.length * 2500); } onMonitor(_frame) { // Split frame (TODO: and join it if is a long one that is splitted in multiple input) var frames = _frame.split("##"); - frames.forEach(function(frame) { + frames.forEach(function (frame) { if (frame == "") return; - if (this.parent != null && this.parent.onMonitor != null && typeof(this.parent.onMonitor) == 'function') this.parent.onMonitor(frame); + if (this.parent != null && this.parent.onMonitor != null && typeof (this.parent.onMonitor) == 'function') this.parent.onMonitor(frame); /* Try to decode as... */ var extract; @@ -206,12 +203,11 @@ class MyHomeClient { if (extract) { let address = this._addressToSlashes(extract[2]); if (extract[1] <= 1) { - if (this.parent != null && this.parent.onMonitor != null && typeof(this.parent.onRelay) == 'function') this.parent.onRelay(address,extract[1] == 1); - debug(sprintf("LIGHTLEVEL %s ADDRESS %s",extract[1],address)); + if (this.parent != null && this.parent.onMonitor != null && typeof (this.parent.onRelay) == 'function') this.parent.onRelay(address, extract[1] == 1); + debug(sprintf("LIGHTLEVEL %s ADDRESS %s", extract[1], address)); } else - if (parseInt(extract[1],10) <= 10) - { - if (this.parent != null && this.parent.onMonitor != null && typeof(this.parent.onDimmer) == 'function') this.parent.onDimmer(address,this.dimmerLevels[parseInt(extract[1],10)]); + if (parseInt(extract[1], 10) <= 10) { + if (this.parent != null && this.parent.onMonitor != null && typeof (this.parent.onDimmer) == 'function') this.parent.onDimmer(address, this.dimmerLevels[parseInt(extract[1], 10)]); } } @@ -220,8 +216,8 @@ class MyHomeClient { extract = frame.match(/^\*#1\*([0-9#]+)\*2\*(\d+)\*(\d+)\*(\d+)$/); if (extract) { let address = this._addressToSlashes(extract[1]); - if (this.parent != null && this.parent.onMonitor != null && typeof(this.parent.onRelayDuration) == 'function') - this.parent.onRelayDuration(address,parseInt(extract[2],10)*3600+parseInt(extract[3],10)*60+parseInt(extract[4],10)); + if (this.parent != null && this.parent.onMonitor != null && typeof (this.parent.onRelayDuration) == 'function') + this.parent.onRelayDuration(address, parseInt(extract[2], 10) * 3600 + parseInt(extract[3], 10) * 60 + parseInt(extract[4], 10)); } /* Light level - Advanced (VantageControls) way */ @@ -229,54 +225,54 @@ class MyHomeClient { extract = frame.match(/^\*#1\*([0-9#]+)\*\d\*(\d+)\*\d+$/); if (extract) { let address = this._addressToSlashes(extract[1]); - if (this.parent != null && this.parent.onMonitor != null && typeof(this.parent.onDimmer) == 'function') this.parent.onDimmer(address,parseInt(extract[2],10)-100); + if (this.parent != null && this.parent.onMonitor != null && typeof (this.parent.onDimmer) == 'function') this.parent.onDimmer(address, parseInt(extract[2], 10) - 100); } /* Simple (F411) Blind */ - extract = frame.match(/^\*2\*(\d)\*([0-9#]+)$/); + extract = frame.match(/^\*2\*(\d)\*([0-9#]+)$/); if (extract) { let address = this._addressToSlashes(extract[2]); - debug(sprintf("BLIND %s ADDRESS %s",extract[1],address)); - if (this.parent != null && this.parent.onMonitor != null && typeof(this.parent.onSimpleBlind) == 'function') this.parent.onSimpleBlind(address,parseInt(extract[1],10)); + debug(sprintf("BLIND %s ADDRESS %s", extract[1], address)); + if (this.parent != null && this.parent.onMonitor != null && typeof (this.parent.onSimpleBlind) == 'function') this.parent.onSimpleBlind(address, parseInt(extract[1], 10)); } /* Advanced (F401) Blind (on stop) */ - extract = frame.match(/^\*#2\*([0-9#]+)\*10\*(\d+)\*(\d+)\*\d+\*\d+$/); + extract = frame.match(/^\*#2\*([0-9#]+)\*10\*(\d+)\*(\d+)\*\d+\*\d+$/); if (extract) { let address = this._addressToSlashes(extract[1]); - let position = parseInt(extract[3],10); + let position = parseInt(extract[3], 10); let direction = "STOP"; - if (parseInt(extract[2],10) == 11) direction = "UP"; - if (parseInt(extract[2],10) == 12) direction = "DOWN"; + if (parseInt(extract[2], 10) == 11) direction = "UP"; + if (parseInt(extract[2], 10) == 12) direction = "DOWN"; - debug(sprintf("ADVANCEDBLIND %s/%s ADDRESS %s",position,direction,address)); - if (this.parent != null && this.parent.onMonitor != null && typeof(this.parent.onSimpleBlind) == 'function') this.parent.onAdvancedBlind(address,direction,position); + debug(sprintf("ADVANCEDBLIND %s/%s ADDRESS %s", position, direction, address)); + if (this.parent != null && this.parent.onMonitor != null && typeof (this.parent.onSimpleBlind) == 'function') this.parent.onAdvancedBlind(address, direction, position); } /* Ambient temperature */ extract = frame.match(/^\*#4\*(\d+)\*[0|14]\*(\d\d\d\d)$/); if (extract) { let address = parseInt(extract[1]); - let temperature = parseFloat(extract[2]/10); + let temperature = parseFloat(extract[2] / 10); if (temperature > 100) { temperature = -(temperature - 100); } - if (this.parent != null && this.parent.onMonitor != null && typeof(this.parent.onThermostat) == 'function') this.parent.onThermostat(address,"AMBIENT",temperature); - debug(sprintf("AMBIENT %s ADDRESS %s",temperature,address)); + if (this.parent != null && this.parent.onMonitor != null && typeof (this.parent.onThermostat) == 'function') this.parent.onThermostat(address, "AMBIENT", temperature); + debug(sprintf("AMBIENT %s ADDRESS %s", temperature, address)); } /* Setpoint temperature */ extract = frame.match(/^\*#4\*(\d+)\*12\*(\d\d\d\d)\*(\d+)$/); if (extract) { let address = parseInt(extract[1]); - let temperature = parseFloat(extract[2]/10); + let temperature = parseFloat(extract[2] / 10); if (temperature > 100) { temperature = -(temperature - 100); } - if (this.parent != null && this.parent.onMonitor != null && typeof(this.parent.onThermostat) == 'function') this.parent.onThermostat(address,"SETPOINT",temperature); - debug(sprintf("SETPOINT %s ADDRESS %s",temperature,address)); + if (this.parent != null && this.parent.onMonitor != null && typeof (this.parent.onThermostat) == 'function') this.parent.onThermostat(address, "SETPOINT", temperature); + debug(sprintf("SETPOINT %s ADDRESS %s", temperature, address)); } // External sensor (see http://www.myopen-legrandgroup.com/community/italian_my_open/italian_65536/f/152/p/1476/7590.aspx#7590) @@ -284,24 +280,24 @@ class MyHomeClient { extract = frame.match(/^\*#4\*(\d+)00\*15\*1\*(\d\d\d\d)\*0001$/); if (extract) { let address = parseInt(extract[1]); - let temperature = parseFloat(extract[2]/10); + let temperature = parseFloat(extract[2] / 10); if (temperature > 100) { temperature = -(temperature - 100); } - if (this.parent != null && this.parent.onMonitor != null && typeof(this.parent.onThermometer) == 'function') this.parent.onThermometer(address,"AMBIENT",temperature); - debug(sprintf("EXT-AMBIENT %s ADDRESS %s",temperature,address)); - } + if (this.parent != null && this.parent.onMonitor != null && typeof (this.parent.onThermometer) == 'function') this.parent.onThermometer(address, "AMBIENT", temperature); + debug(sprintf("EXT-AMBIENT %s ADDRESS %s", temperature, address)); + } // new regex:thActuators = RegEx_Create( \"^\*#4\*(\d{1,2})\*19\*(\d)\*(\d)$" ); extract = frame.match(/^\*#4\*(\d+)\*19\*(\d)\*(\d)$/); if (extract) { let address = parseInt(extract[1]); - let cooling = inArray(extract[2],[1,2]); - let heating = inArray(extract[3],[1,2]); - if (this.parent != null && this.parent.onMonitor != null && typeof(this.parent.onThermostat) == 'function') this.parent.onThermostat(address,"HEATING",heating); - if (this.parent != null && this.parent.onMonitor != null && typeof(this.parent.onThermostat) == 'function') this.parent.onThermostat(address,"COOLING",cooling); - debug(sprintf("HEATING %s COOLING %s ADDRESS %s",heating,cooling,address)); - } + let cooling = inArray(extract[2], [1, 2]); + let heating = inArray(extract[3], [1, 2]); + if (this.parent != null && this.parent.onMonitor != null && typeof (this.parent.onThermostat) == 'function') this.parent.onThermostat(address, "HEATING", heating); + if (this.parent != null && this.parent.onMonitor != null && typeof (this.parent.onThermostat) == 'function') this.parent.onThermostat(address, "COOLING", cooling); + debug(sprintf("HEATING %s COOLING %s ADDRESS %s", heating, cooling, address)); + } // *#4*#*20*## extract = frame.match(/^\*#4\*(\d+)#\d\*20\*\d$/); @@ -314,161 +310,161 @@ class MyHomeClient { // *25*32#[0-1]*3## -> Open (0 after a state request, 1 after an event) -> FALSE extract = frame.match(/^\*25\*3(\d)#[0-1]\*3(\d+)$/); if (extract) { - let value = parseInt(extract[1],10) == 1 ? true : false; - let address = parseInt(extract[2],10); - if (this.parent != null && this.parent.onMonitor != null && typeof(this.parent.onDryContact) == 'function') this.parent.onDryContact(address,value); - debug(sprintf("DRYCONTACT %s ADDRESS %s",value,address)); - } - - // AUX: *9*[0,9]*## OFF - // AUX: *9*1*## ON + let value = parseInt(extract[1], 10) == 1 ? true : false; + let address = parseInt(extract[2], 10); + if (this.parent != null && this.parent.onMonitor != null && typeof (this.parent.onDryContact) == 'function') this.parent.onDryContact(address, value); + debug(sprintf("DRYCONTACT %s ADDRESS %s", value, address)); + } + + // AUX: *9*[0,9]*## OFF + // AUX: *9*1*## ON extract = frame.match(/^\*9\*(\d)\*(\d)$/); if (extract) { let value = false; - if (parseInt(extract[1],10) == 0 || parseInt(extract[1],10)==9) - value = false; + if (parseInt(extract[1], 10) == 0 || parseInt(extract[1], 10) == 9) + value = false; else - value = true; - let address = parseInt(extract[2],10); - if (this.parent != null && this.parent.onMonitor != null && typeof(this.parent.onAUX) == 'function') - this.parent.onAUX(address,value); - debug(sprintf("AUX %s ADDRESS %s",value,address)); - } - + value = true; + let address = parseInt(extract[2], 10); + if (this.parent != null && this.parent.onMonitor != null && typeof (this.parent.onAUX) == 'function') + this.parent.onAUX(address, value); + debug(sprintf("AUX %s ADDRESS %s", value, address)); + } + // Scenario: *17*3*## Enable // Scenario: *17*4*## Disable extract = frame.match(/^\*17\*(\d)\*(\d+)$/); if (extract) { let value = false; - if (parseInt(extract[1],10) == 3) - value = true; - if (parseInt(extract[1],10) == 4) - value = false; - let address = parseInt(extract[2],10); - if (this.parent != null && this.parent.onMonitor != null && typeof(this.parent.onScenario) == 'function') - this.parent.onScenario(address,value); - debug(sprintf("Scenario %s ADDRESS %s",value,address)); - } + if (parseInt(extract[1], 10) == 3) + value = true; + if (parseInt(extract[1], 10) == 4) + value = false; + let address = parseInt(extract[2], 10); + if (this.parent != null && this.parent.onMonitor != null && typeof (this.parent.onScenario) == 'function') + this.parent.onScenario(address, value); + debug(sprintf("Scenario %s ADDRESS %s", value, address)); + } //powermeter extract = frame.match(/^\*#3\*10\*3\*(\d+)$/); if (extract) { - let value = parseInt(extract[1],10); - if (this.parent != null && this.parent.onMonitor != null && typeof(this.parent.onPowerMeter) == 'function') - this.parent.onPowerMeter(value); - debug(sprintf("Power %s W",value)); - } + let value = parseInt(extract[1], 10); + if (this.parent != null && this.parent.onMonitor != null && typeof (this.parent.onPowerMeter) == 'function') + this.parent.onPowerMeter(value); + debug(sprintf("Power %s W", value)); + } // //controlled load extract = frame.match(/^\*3\*(\d)\*#(\d)$/); if (extract) { - let value = parseInt(extract[1],10); - let address = parseInt(extract[2],10); - if (this.parent != null && this.parent.onMonitor != null && typeof(this.parent.onControlledLoad) == 'function') - this.parent.onControlledLoad(address,value); - } + let value = parseInt(extract[1], 10); + let address = parseInt(extract[2], 10); + if (this.parent != null && this.parent.onMonitor != null && typeof (this.parent.onControlledLoad) == 'function') + this.parent.onControlledLoad(address, value); + } //alarm status extract = frame.match(/^\*5\*(\d+)\*0*$/); if (extract) { - let value = parseInt(extract[1],10); - switch (value){ - case 0: - - break; - case 1: - - break; - case 8: //engaged - if (this.parent != null && this.parent.onMonitor != null && typeof(this.parent.onAlarm) == 'function') - this.parent.onAlarm(1); - break; - case 9: //disengaged - if (this.parent != null && this.parent.onMonitor != null && typeof(this.parent.onAlarm) == 'function') - this.parent.onAlarm(3); - if (this.parent != null && this.parent.onMonitor != null && typeof(this.parent.onAlarmTampered) == 'function') - this.parent.onAlarmTampered(0); - break; - case 4: - case 10: //battery KO - if (this.parent != null && this.parent.onMonitor != null && typeof(this.parent.onAlarmLowBattery) == 'function') - this.parent.onAlarmLowBattery(1); - break; - case 5: //battery OK - if (this.parent != null && this.parent.onMonitor != null && typeof(this.parent.onAlarmLowBattery) == 'function') - this.parent.onAlarmLowBattery(0); - break; - case 6: //no network - if (this.parent != null && this.parent.onMonitor != null && typeof(this.parent.onAlarmFault) == 'function') - this.parent.onAlarmFault(1); - break; - case 7: //network ok - if (this.parent != null && this.parent.onMonitor != null && typeof(this.parent.onAlarmFault) == 'function') - this.parent.onAlarmFault(0); - break; - default: - } - } - + let value = parseInt(extract[1], 10); + switch (value) { + case 0: + + break; + case 1: + + break; + case 8: //engaged + if (this.parent != null && this.parent.onMonitor != null && typeof (this.parent.onAlarm) == 'function') + this.parent.onAlarm(1); + break; + case 9: //disengaged + if (this.parent != null && this.parent.onMonitor != null && typeof (this.parent.onAlarm) == 'function') + this.parent.onAlarm(3); + if (this.parent != null && this.parent.onMonitor != null && typeof (this.parent.onAlarmTampered) == 'function') + this.parent.onAlarmTampered(0); + break; + case 4: + case 10: //battery KO + if (this.parent != null && this.parent.onMonitor != null && typeof (this.parent.onAlarmLowBattery) == 'function') + this.parent.onAlarmLowBattery(1); + break; + case 5: //battery OK + if (this.parent != null && this.parent.onMonitor != null && typeof (this.parent.onAlarmLowBattery) == 'function') + this.parent.onAlarmLowBattery(0); + break; + case 6: //no network + if (this.parent != null && this.parent.onMonitor != null && typeof (this.parent.onAlarmFault) == 'function') + this.parent.onAlarmFault(1); + break; + case 7: //network ok + if (this.parent != null && this.parent.onMonitor != null && typeof (this.parent.onAlarmFault) == 'function') + this.parent.onAlarmFault(0); + break; + default: + } + } + //alarm triggered and zone selection extract = frame.match(/^\*5\*(\d+)\*#(\d)$/); if (extract) { - let value = parseInt(extract[1],10); - switch (value){ - case 11: //zone active - if (this.parent != null && this.parent.onMonitor != null && typeof(this.parent.onZoneActive) == 'function') - this.parent.onZoneActive(parseInt(extract[2],10)-1, true); - break; - case 18: //zone deactive - if (this.parent != null && this.parent.onMonitor != null && typeof(this.parent.onZoneActive) == 'function') - this.parent.onZoneActive(parseInt(extract[2],10)-1, false); - break; - case 15: //silent alarm - case 17: //intrusion - if (this.parent != null && this.parent.onMonitor != null && typeof(this.parent.onAlarm) == 'function') - this.parent.onAlarm(4); - break; - case 16: //tampering - if (this.parent != null && this.parent.onMonitor != null && typeof(this.parent.onAlarmTampered) == 'function') - this.parent.onAlarmTampered(1); - break; - default: - } - } + let value = parseInt(extract[1], 10); + switch (value) { + case 11: //zone active + if (this.parent != null && this.parent.onMonitor != null && typeof (this.parent.onZoneActive) == 'function') + this.parent.onZoneActive(parseInt(extract[2], 10) - 1, true); + break; + case 18: //zone deactive + if (this.parent != null && this.parent.onMonitor != null && typeof (this.parent.onZoneActive) == 'function') + this.parent.onZoneActive(parseInt(extract[2], 10) - 1, false); + break; + case 15: //silent alarm + case 17: //intrusion + if (this.parent != null && this.parent.onMonitor != null && typeof (this.parent.onAlarm) == 'function') + this.parent.onAlarm(4); + break; + case 16: //tampering + if (this.parent != null && this.parent.onMonitor != null && typeof (this.parent.onAlarmTampered) == 'function') + this.parent.onAlarmTampered(1); + break; + default: + } + } }.bind(this)); } getThermostatStatus(_address) { - this.command.send(sprintf("*#4*%d##*#4*19*%d##",_address,_address)); + this.command.send(sprintf("*#4*%d##*#4*19*%d##", _address, _address)); } getContactState(_address) { - this.command.send(sprintf("*#25*3%d##",_address)); + this.command.send(sprintf("*#25*3%d##", _address)); } getScenarioState(_address) { - this.command.send(sprintf("*#17*%d##",_address)); + this.command.send(sprintf("*#17*%d##", _address)); } - + getRelayState(_address) { - this.command.send(sprintf("*#1*%s##",this._slashesToAddress(_address))); + this.command.send(sprintf("*#1*%s##", this._slashesToAddress(_address))); } getRelayDuration(_address) { - this.command.send(sprintf("*#1*%s*2##",this._slashesToAddress(_address))); + this.command.send(sprintf("*#1*%s*2##", this._slashesToAddress(_address))); } getAdvancedBlindState(_address) { - this.command.send(sprintf("*#2*%s*10##",this._slashesToAddress(_address))); + this.command.send(sprintf("*#2*%s*10##", this._slashesToAddress(_address))); } - getPower(){ + getPower() { this.command.send("*#3*10*3##"); } - getAlarmState(){ + getAlarmState() { this.command.send("*#5*0##"); } @@ -487,11 +483,11 @@ class MyHomeClient { */ class MyHomeConnection { - constructor(_ipaddress, _port, _password, _type, _onconnectcallback, _onmessagecallback, _setclock) { + constructor(_ipaddress, _port, _password, _type, _onconnectcallback, _onmessagecallback, _setclock) { this.ipaddress = _ipaddress; this.password = _password; this.type = _type; - this.port = parseInt(_port,10); + this.port = parseInt(_port, 10); this.state = 0; this.expected = ""; this.isConnected = false; @@ -504,7 +500,7 @@ class MyHomeConnection { this.reconnecthandle = null; this.disconnecthandle = null; this.setclock = _setclock; - + this.keepaliveSeconds = 25; /* Send keepalive command frame every 25 seconds */ this.idleSeconds = 55; /* Drop idle/lost connections after 55 seconds */ this.reconnectSeconds = 5; /* reconnect after 5 seconds */ @@ -512,24 +508,24 @@ class MyHomeConnection { /* Keepalive frame on command connection every this.keepaliveSeconds seconds */ if (this.type == "COMMAND") { - setInterval(function(){ this.sendKeepalive(); }.bind(this), this.keepaliveSeconds * 1000); + setInterval(function () { this.sendKeepalive(); }.bind(this), this.keepaliveSeconds * 1000); if (this.setclock) - setInterval(function(){ this.updateDate(); }.bind(this), this.updateTimeSeconds * 1000); + setInterval(function () { this.updateDate(); }.bind(this), this.updateTimeSeconds * 1000); } this.connect(); } connect() { - this.connection = net.connect({ host: this.ipaddress, port: this.port }, () => {}); + this.connection = net.connect({ host: this.ipaddress, port: this.port }, () => { }); if (this.reconnecthandle != null) { clearTimeout(this.reconnecthandle); this.reconnecthandle = null; } /* Disconnect after this.idleSeconds seconds of inactivity */ if (this.disconnecthandle != null) clearTimeout(this.disconnecthandle); - this.disconnecthandle = setTimeout(function() { + this.disconnecthandle = setTimeout(function () { debug('Info[%s]: Stale connection detected, drop it!', this.type); - this.connection.end(); + this.connection.end(); }.bind(this), this.idleSeconds * 1000); this.connection.on('data', (_in) => { @@ -537,13 +533,13 @@ class MyHomeConnection { /* Disconnect after this.idleSeconds seconds of inactivity */ if (this.disconnecthandle != null) clearTimeout(this.disconnecthandle); - this.disconnecthandle = setTimeout(function() { + this.disconnecthandle = setTimeout(function () { debug('Info[%s]: Stale connection detected, drop it!', this.type); - this.connection.end(); + this.connection.end(); }.bind(this), this.idleSeconds * 1000); var data = _in.toString().trim(); - debug('Received[%s]: <%s>', this.type, data); + debug('Received[%s]: <%s>', this.type, data); if (this.state == 0 && data == "*#*1##") { /* * Great, answers and is ready to talk with me, I send @@ -561,7 +557,7 @@ class MyHomeConnection { debug('Info[%s]: Unauthenticated connection', this.type); this.state = 100; - this.buffer.forEach(function(item, index, object) { + this.buffer.forEach(function (item, index, object) { this.write(this.buffer[index]); this.buffer.splice(index, 1); }.bind(this)); @@ -571,7 +567,7 @@ class MyHomeConnection { /* OPEN auth, there's a rosetta implementation that "can be used" */ debug('Info[%s]: OWN Password Supported, try to answer', this.type); this.state = 21; - this.write(sprintf("*#%s##",this.openwebnetAnswer(this.password,data.match(/^\*#(\d{8,12})##$/)[1]))); + this.write(sprintf("*#%s##", this.openwebnetAnswer(this.password, data.match(/^\*#(\d{8,12})##$/)[1]))); } else if (this.state == 1 && data == "*98*2##") { /* HMAC is supported, ok let's try */ this.state = 10; @@ -580,7 +576,7 @@ class MyHomeConnection { } else if (this.state == 10) { /* RA offered, we can calc answer */ this.state = 11; - var ra = data.substring(2,data.length-2); + var ra = data.substring(2, data.length - 2); var hmac = this.calcHMAC(ra); this.write(hmac); debug('Info[%s]: HMAC Supported, proceed with phase 2', this.type); @@ -589,7 +585,7 @@ class MyHomeConnection { /* Yeah, connection is up! */ this.state = 100; this.write("*#*1##"); - this.buffer.forEach(function(item, index, object) { + this.buffer.forEach(function (item, index, object) { this.write(this.buffer[index]); this.buffer.splice(index, 1); }.bind(this)); @@ -606,7 +602,7 @@ class MyHomeConnection { if (data == "*#*1##") { debug('Info[%s]: OWN Password authenticated with success', this.type); this.state = 100; - this.buffer.forEach(function(item, index, object) { + this.buffer.forEach(function (item, index, object) { this.write(this.buffer[index]); this.buffer.splice(index, 1); }.bind(this)); @@ -624,7 +620,7 @@ class MyHomeConnection { this.state = 0; this.isConnected = false; if (this.reconnecthandle != null) clearTimeout(this.reconnecthandle); - this.reconnecthandle = setTimeout(function() { + this.reconnecthandle = setTimeout(function () { debug('Info[%s]: Try to reconnect !', this.type); this.connect(); }.bind(this), this.reconnectSeconds * 1000); @@ -634,18 +630,18 @@ class MyHomeConnection { this.state = 0; this.isConnected = false; if (this.reconnecthandle != null) clearTimeout(this.reconnecthandle); - this.reconnecthandle = setTimeout(function() { + this.reconnecthandle = setTimeout(function () { debug('Info[%s]: Try to reconnect !', this.type); this.connect(); }.bind(this), this.reconnectSeconds * 1000); - }); + }); } /** * OWN Password implementation that can be found on the web, it seems to work */ - openwebnetAnswer(pass,nonce) { - var _0x9148=["\x30","\x31","\x32","\x33","\x34","\x35","\x36","\x37","\x38","\x39"];var _0xba8b=[_0x9148[0],_0x9148[1],_0x9148[2],_0x9148[3],_0x9148[4],_0x9148[5],_0x9148[6],_0x9148[7],_0x9148[8],_0x9148[9]];var flag=true;var num1=0x0;var num2=0x0;var password=parseInt(pass,10);for(var c in nonce){c= nonce[c];if(c!= _0xba8b[0]){if(flag){num2= password;}flag= false;}switch(c){case _0xba8b[1]:num1= num2& 0xFFFFFF80;num1= num1>>> 7;num2= num2<< 25;num1= num1+ num2;break;case _0xba8b[2]:num1= num2& 0xFFFFFFF0;num1= num1>>> 4;num2= num2<< 28;num1= num1+ num2;break;case _0xba8b[3]:num1= num2& 0xFFFFFFF8;num1= num1>>> 3;num2= num2<< 29;num1= num1+ num2;break;case _0xba8b[4]:num1= num2<< 1;num2= num2>>> 31;num1= num1+ num2;break;case _0xba8b[5]:num1= num2<< 5;num2= num2>>> 27;num1= num1+ num2;break;case _0xba8b[6]:num1= num2<< 12;num2= num2>>> 20;num1= num1+ num2;break;case _0xba8b[7]:num1= num2& 0x0000FF00;num1= num1+ ((num2& 0x000000FF)<< 24);num1= num1+ ((num2& 0x00FF0000)>>> 16);num2= (num2& 0xFF000000)>>> 8;num1= num1+ num2;break;case _0xba8b[8]:num1= num2& 0x0000FFFF;num1= num1<< 16;num1= num1+ (num2>>> 24);num2= num2& 0x00FF0000;num2= num2>>> 8;num1= num1+ num2;break;case _0xba8b[9]:num1= ~num2;break;case _0xba8b[0]:num1= num2;break;}num2= num1;}return (num1>>> 0).toString(); + openwebnetAnswer(pass, nonce) { + var _0x9148 = ["\x30", "\x31", "\x32", "\x33", "\x34", "\x35", "\x36", "\x37", "\x38", "\x39"]; var _0xba8b = [_0x9148[0], _0x9148[1], _0x9148[2], _0x9148[3], _0x9148[4], _0x9148[5], _0x9148[6], _0x9148[7], _0x9148[8], _0x9148[9]]; var flag = true; var num1 = 0x0; var num2 = 0x0; var password = parseInt(pass, 10); for (var c in nonce) { c = nonce[c]; if (c != _0xba8b[0]) { if (flag) { num2 = password; } flag = false; } switch (c) { case _0xba8b[1]: num1 = num2 & 0xFFFFFF80; num1 = num1 >>> 7; num2 = num2 << 25; num1 = num1 + num2; break; case _0xba8b[2]: num1 = num2 & 0xFFFFFFF0; num1 = num1 >>> 4; num2 = num2 << 28; num1 = num1 + num2; break; case _0xba8b[3]: num1 = num2 & 0xFFFFFFF8; num1 = num1 >>> 3; num2 = num2 << 29; num1 = num1 + num2; break; case _0xba8b[4]: num1 = num2 << 1; num2 = num2 >>> 31; num1 = num1 + num2; break; case _0xba8b[5]: num1 = num2 << 5; num2 = num2 >>> 27; num1 = num1 + num2; break; case _0xba8b[6]: num1 = num2 << 12; num2 = num2 >>> 20; num1 = num1 + num2; break; case _0xba8b[7]: num1 = num2 & 0x0000FF00; num1 = num1 + ((num2 & 0x000000FF) << 24); num1 = num1 + ((num2 & 0x00FF0000) >>> 16); num2 = (num2 & 0xFF000000) >>> 8; num1 = num1 + num2; break; case _0xba8b[8]: num1 = num2 & 0x0000FFFF; num1 = num1 << 16; num1 = num1 + (num2 >>> 24); num2 = num2 & 0x00FF0000; num2 = num2 >>> 8; num1 = num1 + num2; break; case _0xba8b[9]: num1 = ~num2; break; case _0xba8b[0]: num1 = num2; break; }num2 = num1; } return (num1 >>> 0).toString(); } /** @@ -664,9 +660,9 @@ class MyHomeConnection { if (this.buffer.length > 0) { this.write(this.buffer.shift()); if (this.buffer.length > 0) { - this.timerhandle = setTimeout(function() { + this.timerhandle = setTimeout(function () { this.writeBuffer(); - }.bind(this), this.commandms); + }.bind(this), this.commandms); } else { this.timerhandle = null; } @@ -677,7 +673,7 @@ class MyHomeConnection { send(_in) { var frames = _in.split("##"); - frames.forEach(function(frame) { + frames.forEach(function (frame) { if (frame == "") return; frame = frame + "##"; if (this.isConnected) { @@ -688,18 +684,18 @@ class MyHomeConnection { debug('Buffer[%s]: <%s>', this.type, frame); this.buffer.push(frame); if (this.timerhandle == null) { - this.timerhandle = setTimeout(function() { + this.timerhandle = setTimeout(function () { this.writeBuffer(); - }.bind(this), this.commandms); + }.bind(this), this.commandms); } } } else { debug('Buffer[%s]: <%s>', this.type, frame); this.buffer.push(frame); if (this.timerhandle == null) { - this.timerhandle = setTimeout(function() { + this.timerhandle = setTimeout(function () { this.writeBuffer(); - }.bind(this), this.commandms); + }.bind(this), this.commandms); } } }, this); @@ -707,18 +703,16 @@ class MyHomeConnection { sendKeepalive() { debug('Keealive[%s]: send keepalive', this.type); - if (this.isConnected) - { + if (this.isConnected) { this.connection.write("*#13**15##"); - } + } } - updateDate(){ - if (this.isConnected) - { + updateDate() { + if (this.isConnected) { var setDateTimeFrame = moment().format("*#13**#22*HH*mm*ss*001*0d*DD*MM*YYYY##"); this.connection.write(setDateTimeFrame); - + } } @@ -727,16 +721,16 @@ class MyHomeConnection { /* TODO: SHA1 */ } else if (_in.length == 128) { var rb = crypto.createHmac('sha256', "pimperepettenusa").digest('hex'); - var message = sha256(this.digitToHex(_in)+rb+"736F70653E"+"636F70653E"+sha256(this.password)); - this.answer = sprintf("*#%s##", this.hexToDigit(sha256(this.digitToHex(_in)+rb+sha256(this.password)))).trim(); - return sprintf("*#%s*%s##", this.hexToDigit(rb),this.hexToDigit(message)); + var message = sha256(this.digitToHex(_in) + rb + "736F70653E" + "636F70653E" + sha256(this.password)); + this.answer = sprintf("*#%s##", this.hexToDigit(sha256(this.digitToHex(_in) + rb + sha256(this.password)))).trim(); + return sprintf("*#%s*%s##", this.hexToDigit(rb), this.hexToDigit(message)); } } digitToHex(_in) { var out = ""; - for (var i = 0; i < _in.length; i = i+4) { - out = out + (parseInt(_in[i])*10+parseInt(_in[i+1])).toString(16) + (parseInt(_in[i+2])*10+parseInt(_in[i+3])).toString(16); + for (var i = 0; i < _in.length; i = i + 4) { + out = out + (parseInt(_in[i]) * 10 + parseInt(_in[i + 1])).toString(16) + (parseInt(_in[i + 2]) * 10 + parseInt(_in[i + 3])).toString(16); } return out; } @@ -744,7 +738,7 @@ class MyHomeConnection { hexToDigit(_in) { var out = ""; for (var i = 0; i < _in.length; i++) { - out = out + sprintf("%d%d", parseInt(_in[i],16)/10,parseInt(_in[i],16)%10); + out = out + sprintf("%d%d", parseInt(_in[i], 16) / 10, parseInt(_in[i], 16) % 10); } return out; } From c9c8f480aa221280cec45d26b7a86dbd09ab1b9e Mon Sep 17 00:00:00 2001 From: simont77 <26008536+simont77@users.noreply.github.com> Date: Sun, 20 May 2018 17:31:54 +0200 Subject: [PATCH 70/96] update MHScenario with both Active and Esegui --- index.js | 47 +++++++++++++++++++++++++++++++++++++++++++---- lib/mhclient.js | 18 +++++++++++++----- 2 files changed, 56 insertions(+), 9 deletions(-) diff --git a/index.js b/index.js index c36d153..27d38f5 100644 --- a/index.js +++ b/index.js @@ -129,6 +129,17 @@ module.exports = function (homebridge) { LegrandMyHome.Char119.UUID = 'E863F119-079E-48FF-8F27-9C2605A29F52'; inherits(LegrandMyHome.Char119, Characteristic); + LegrandMyHome.SimpleBoolean = function () { + Characteristic.call(this, 'Esegui', '6C716596-A86D-4810-86A7-6F258DE448C3'); + this.setProps({ + format: Characteristic.Formats.BOOL, + perms: [Characteristic.Perms.READ, Characteristic.Perms.WRITE, Characteristic.Perms.NOTIFY] + }); + this.value = this.getDefaultValue(); + }; + LegrandMyHome.TimesOpened.UUID = '6C716596-A86D-4810-86A7-6F258DE448C3'; + inherits(LegrandMyHome.SimpleBoolean, Characteristic); + LegrandMyHome.PowerMeterService = function (displayName, subtype) { Service.call(this, displayName, '00000001-0000-1777-8000-775D67EC4377', subtype); this.addCharacteristic(LegrandMyHome.CurrentPowerConsumption); @@ -147,6 +158,13 @@ module.exports = function (homebridge) { }; inherits(LegrandMyHome.ControlledLoadService, Service); + LegrandMyHome.ScenarioService = function (displayName, subtype) { + Service.call(this, displayName, '524C7C75-1D86-44BA-A923-554BDA240EE5', subtype); + this.addCharacteristic(Characteristic.Active); + this.addCharacteristic(LegrandMyHome.SimpleBoolean); + }; + inherits(LegrandMyHome.ScenarioService, Service); + LegrandMyHome.RainSensorService = function (displayName, subtype) { Service.call(this, displayName, '9018CDC8-DEF9-49D5-A969-63F8CCAAB1A6', subtype); this.addCharacteristic(Characteristic.CurrentRelativeHumidity); @@ -288,11 +306,20 @@ class LegrandMyHome { }.bind(this)); } - onScenario(_address, _state) { + onScenarioEnable(_address, _state) { this.devices.forEach(function (accessory) { if (accessory.scenarioService !== undefined && accessory.address == _address) { accessory.state = _state; - accessory.scenarioService.getCharacteristic(Characteristic.On).getValue(null); + accessory.scenarioService.getCharacteristic(Characteristic.Active).getValue(null); + } + }.bind(this)); + } + + onScenarioRun(_address, _state) { + this.devices.forEach(function (accessory) { + if (accessory.scenarioService !== undefined && accessory.address == _address) { + accessory.running = _state; + accessory.scenarioService.getCharacteristic(LegrandMyHome.SimpleBoolean).getValue(null); } }.bind(this)); } @@ -1404,6 +1431,7 @@ class MHScenario { this.log = log; this.state = 0; + this.running = 0; this.log.info(sprintf("LegrandMyHome::MHScenario create object: %s", this.address)); } @@ -1415,8 +1443,8 @@ class MHScenario { .setCharacteristic(Characteristic.FirmwareRevision, version) .setCharacteristic(Characteristic.SerialNumber, "Address " + this.address); - this.scenarioService = new Service.Switch(this.name); - this.scenarioService.getCharacteristic(Characteristic.On) + this.scenarioService = new LegrandMyHome.ScenarioService(this.name); + this.scenarioService.getCharacteristic(Characteristic.Active) .on('set', (value, callback) => { this.state = value; this.mh.enableScenarioCommand(this.address, this.state); @@ -1427,6 +1455,17 @@ class MHScenario { this.log.debug(sprintf("getOn %s", this.address)); callback(null, this.state); }); + this.scenarioService.getCharacteristic(LegrandMyHome.SimpleBoolean) + .on('set', (value, callback) => { + this.running = value; + this.mh.runScenarioCommand(this.address, this.running); + this.log.debug(sprintf("runOn %s = %s", this.address, this.state)); + callback(null); + }) + .on('get', (callback) => { + this.log.debug(sprintf("getOn %s", this.address)); + callback(null, this.running); + }); return [service, this.scenarioService]; } diff --git a/lib/mhclient.js b/lib/mhclient.js index ead95ca..0880097 100755 --- a/lib/mhclient.js +++ b/lib/mhclient.js @@ -157,6 +157,11 @@ class MyHomeClient { this.command.send(sprintf("*17*%d*%s##", (_status) ? 3 : 4, _address)); } + runScenarioCommand(_address, _status) { + if (_address == "") return; + this.command.send(sprintf("*17*%d*%s##", (_status) ? 1 : 2, _address)); + } + setSetPoint(_address, _temperature) { // Standard thermostat *4*40*%02d##*#4*#%02d*#14*%04d*3 this._bufferCommand("THERMO", _address, sprintf("*4*40*%02d##*#4*#%02d*#14*%04d*3##*#4*%02d*14##", _address, _address, _temperature * 10, _address), 500); @@ -331,18 +336,21 @@ class MyHomeClient { debug(sprintf("AUX %s ADDRESS %s", value, address)); } + // Scenario: *17*1*## Start + // Scenario: *17*2*## Stop // Scenario: *17*3*## Enable // Scenario: *17*4*## Disable extract = frame.match(/^\*17\*(\d)\*(\d+)$/); if (extract) { let value = false; - if (parseInt(extract[1], 10) == 3) + let command = parseInt(extract[1], 10); + if ((command == 3) || (command == 1)) value = true; - if (parseInt(extract[1], 10) == 4) - value = false; let address = parseInt(extract[2], 10); - if (this.parent != null && this.parent.onMonitor != null && typeof (this.parent.onScenario) == 'function') - this.parent.onScenario(address, value); + if (this.parent != null && this.parent.onMonitor != null && typeof (this.parent.onScenarioEnable) == 'function' && (command == 3 || command == 4)) + this.parent.onScenarioEnable(address, value); + if (this.parent != null && this.parent.onMonitor != null && typeof (this.parent.onScenarioRun) == 'function' && (command == 1 || command == 2)) + this.parent.onScenarioRun(address, value); debug(sprintf("Scenario %s ADDRESS %s", value, address)); } From 8b94521428f173d10b8fd46fd7dea78dbbdf18c8 Mon Sep 17 00:00:00 2001 From: simont77 <26008536+simont77@users.noreply.github.com> Date: Sun, 20 May 2018 17:32:58 +0200 Subject: [PATCH 71/96] 0.1.12 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 54d25aa..6465fc8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-myhome-tng", - "version": "0.1.11", + "version": "0.1.12", "description": "Legrand MyHome plugin for homebridge: https://github.com/nfarina/homebridge", "license": "MIT", "keywords": [ From 94cbdf6ecb31fe4820aab3bd1f34439fd9c17bb3 Mon Sep 17 00:00:00 2001 From: simont77 <26008536+simont77@users.noreply.github.com> Date: Tue, 26 Jun 2018 23:38:23 +0200 Subject: [PATCH 72/96] initial support to irrigation history (stil to be fixed) --- index.js | 42 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 37 insertions(+), 5 deletions(-) diff --git a/index.js b/index.js index 27d38f5..7667c49 100644 --- a/index.js +++ b/index.js @@ -7,6 +7,9 @@ var Accessory, Characteristic, Service, UUIDGen; var moment = require('moment'); var correctingInterval = require('correcting-interval'); const version = require('./package.json').version; +var hexToBase64 = function (val) { + return new Buffer(('' + val).replace(/[^0-9A-F]/ig, ''), 'hex').toString('base64'); +}; module.exports = function (homebridge) { Service = homebridge.hap.Service; @@ -129,6 +132,28 @@ module.exports = function (homebridge) { LegrandMyHome.Char119.UUID = 'E863F119-079E-48FF-8F27-9C2605A29F52'; inherits(LegrandMyHome.Char119, Characteristic); + LegrandMyHome.Char131 = function () { + Characteristic.call(this, 'Char131', 'E863F131-079E-48FF-8F27-9C2605A29F52'); + this.setProps({ + format: Characteristic.Formats.DATA, + perms: [Characteristic.Perms.READ, Characteristic.Perms.WRITE, Characteristic.Perms.NOTIFY] + }); + this.value = this.getDefaultValue(); + }; + LegrandMyHome.Char131.UUID = 'E863F131-079E-48FF-8F27-9C2605A29F52'; + inherits(LegrandMyHome.Char131, Characteristic); + + LegrandMyHome.Char11D = function () { + Characteristic.call(this, 'Char11D', 'E863F11D-079E-48FF-8F27-9C2605A29F52'); + this.setProps({ + format: Characteristic.Formats.DATA, + perms: [Characteristic.Perms.READ, Characteristic.Perms.WRITE, Characteristic.Perms.NOTIFY] + }); + this.value = this.getDefaultValue(); + }; + LegrandMyHome.Char11D.UUID = 'E863F11D-079E-48FF-8F27-9C2605A29F52'; + inherits(LegrandMyHome.Char11D, Characteristic); + LegrandMyHome.SimpleBoolean = function () { Characteristic.call(this, 'Esegui', '6C716596-A86D-4810-86A7-6F258DE448C3'); this.setProps({ @@ -1895,17 +1920,24 @@ class MHIrrigation { this.IrrigationService = new Service.Valve(this.name); - // just to make the irrigation icon show in Eve, real history signature needed + this.IrrigationService.addCharacteristic(LegrandMyHome.LastActivation); if (this.config.storage == 'fs') - this.LoggingService = new LegrandMyHome.FakeGatoHistoryService("motion", this, { storage: 'fs', disableTimer: true }); + this.LoggingService = new LegrandMyHome.FakeGatoHistoryService("aqua", this, { storage: 'fs', disableTimer: true }); else - this.LoggingService = new LegrandMyHome.FakeGatoHistoryService("motion", this, { storage: 'googleDrive', path: 'homebridge', disableTimer: true }); + this.LoggingService = new LegrandMyHome.FakeGatoHistoryService("aqua", this, { storage: 'googleDrive', path: 'homebridge', disableTimer: true }); this.ExtraPersistedData = this.LoggingService.getExtraPersistedData(); if (this.ExtraPersistedData != undefined) { this.lastActivation = this.ExtraPersistedData.lastActivation || 0; } - + this.IrrigationService.addCharacteristic(Characteristic.LockPhysicalControls); + this.IrrigationService.addCharacteristic(Characteristic.RemainingDuration); + this.IrrigationService.addCharacteristic(Characteristic.StatusFault); + this.IrrigationService.removeCharacteristic(Characteristic.ServiceLabelIndex); + this.IrrigationService.removeCharacteristic(Characteristic.IsConfigured); + this.LoggingService.addCharacteristic(LegrandMyHome.Char11D); + this.LoggingService.addCharacteristic(LegrandMyHome.Char131); + //this.LoggingService.setCharacteristic(LegrandMyHome.Char131,hexToBase64('0002230003021b04040c4156323248314130303036330602080007042a3000000b0200000501000204f82c00001401030f0400000000450505000000004609050000000e000042064411051c0005033c0000003a814b42a34d8c4047110594186d19071ad91ab40000003c00000048060500000000004a06050000000000d004 79010000 9b047c01 00002f0e e00f0100 00000000 00000000 2c01 2d06 0000000000001e02300c')); this.IrrigationService.setCharacteristic(Characteristic.ValveType, 1); this.IrrigationService.setCharacteristic(Characteristic.SetDuration, this.timer); this.IrrigationService.getCharacteristic(Characteristic.Active) @@ -1947,7 +1979,7 @@ class MHIrrigation { this.log.debug(sprintf("changeIrrigation %s = %s", this.address, this.power)); this.lastActivation = moment().unix() - this.LoggingService.getInitialTime(); this.LoggingService.setExtraPersistedData({ lastActivation: this.lastActivation }); - this.LoggingService.addEntry({ time: moment().unix(), status: this.power }); + this.LoggingService.addEntry({ time: moment().unix(), status: this.power, waterAmount:1000 }); }); this.IrrigationService.getCharacteristic(Characteristic.SetDuration) .on('set', (time, callback) => { From c6140b657a6dc1eafb8789a6f4539623e2982554 Mon Sep 17 00:00:00 2001 From: simont77 <26008536+simont77@users.noreply.github.com> Date: Wed, 27 Jun 2018 08:28:36 +0200 Subject: [PATCH 73/96] fix to irrigation serial number --- index.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/index.js b/index.js index 7667c49..ba56075 100644 --- a/index.js +++ b/index.js @@ -1916,7 +1916,7 @@ class MHIrrigation { .setCharacteristic(Characteristic.Manufacturer, "Simone Tisa") .setCharacteristic(Characteristic.Model, "Irrigation") .setCharacteristic(Characteristic.FirmwareRevision, version) - .setCharacteristic(Characteristic.SerialNumber, "Address " + this.address); + .setCharacteristic(Characteristic.SerialNumber, "Address " + this.bus + "-" + this.ambient + "-" + this.pl); this.IrrigationService = new Service.Valve(this.name); @@ -1930,11 +1930,11 @@ class MHIrrigation { if (this.ExtraPersistedData != undefined) { this.lastActivation = this.ExtraPersistedData.lastActivation || 0; } - this.IrrigationService.addCharacteristic(Characteristic.LockPhysicalControls); - this.IrrigationService.addCharacteristic(Characteristic.RemainingDuration); - this.IrrigationService.addCharacteristic(Characteristic.StatusFault); - this.IrrigationService.removeCharacteristic(Characteristic.ServiceLabelIndex); - this.IrrigationService.removeCharacteristic(Characteristic.IsConfigured); + //this.IrrigationService.addCharacteristic(Characteristic.LockPhysicalControls); + //this.IrrigationService.addCharacteristic(Characteristic.RemainingDuration); + //this.IrrigationService.addCharacteristic(Characteristic.StatusFault); + //this.IrrigationService.removeCharacteristic(Characteristic.ServiceLabelIndex); + //this.IrrigationService.removeCharacteristic(Characteristic.IsConfigured); this.LoggingService.addCharacteristic(LegrandMyHome.Char11D); this.LoggingService.addCharacteristic(LegrandMyHome.Char131); //this.LoggingService.setCharacteristic(LegrandMyHome.Char131,hexToBase64('0002230003021b04040c4156323248314130303036330602080007042a3000000b0200000501000204f82c00001401030f0400000000450505000000004609050000000e000042064411051c0005033c0000003a814b42a34d8c4047110594186d19071ad91ab40000003c00000048060500000000004a06050000000000d004 79010000 9b047c01 00002f0e e00f0100 00000000 00000000 2c01 2d06 0000000000001e02300c')); From c99b7858bf3606d280d12571ac0c28b0cff1090c Mon Sep 17 00:00:00 2001 From: simont77 <26008536+simont77@users.noreply.github.com> Date: Thu, 28 Jun 2018 11:01:08 +0200 Subject: [PATCH 74/96] adding extra char for irrigation, work in progress --- index.js | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/index.js b/index.js index ba56075..44e6ef7 100644 --- a/index.js +++ b/index.js @@ -7,9 +7,20 @@ var Accessory, Characteristic, Service, UUIDGen; var moment = require('moment'); var correctingInterval = require('correcting-interval'); const version = require('./package.json').version; +const Format = require('util').format; var hexToBase64 = function (val) { return new Buffer(('' + val).replace(/[^0-9A-F]/ig, ''), 'hex').toString('base64'); }; +var numToHex = function (val, len) { + var s = Number(val >>> 0).toString(16); + if (s.length % 2 != 0) { + s = '0' + s; + } + if (len) { + return ('0000000000000' + s).slice(-1 * len); + } + return s; +}; module.exports = function (homebridge) { Service = homebridge.hap.Service; @@ -1930,16 +1941,23 @@ class MHIrrigation { if (this.ExtraPersistedData != undefined) { this.lastActivation = this.ExtraPersistedData.lastActivation || 0; } - //this.IrrigationService.addCharacteristic(Characteristic.LockPhysicalControls); - //this.IrrigationService.addCharacteristic(Characteristic.RemainingDuration); - //this.IrrigationService.addCharacteristic(Characteristic.StatusFault); - //this.IrrigationService.removeCharacteristic(Characteristic.ServiceLabelIndex); - //this.IrrigationService.removeCharacteristic(Characteristic.IsConfigured); + this.LoggingService.addCharacteristic(LegrandMyHome.Char11D); this.LoggingService.addCharacteristic(LegrandMyHome.Char131); //this.LoggingService.setCharacteristic(LegrandMyHome.Char131,hexToBase64('0002230003021b04040c4156323248314130303036330602080007042a3000000b0200000501000204f82c00001401030f0400000000450505000000004609050000000e000042064411051c0005033c0000003a814b42a34d8c4047110594186d19071ad91ab40000003c00000048060500000000004a06050000000000d004 79010000 9b047c01 00002f0e e00f0100 00000000 00000000 2c01 2d06 0000000000001e02300c')); this.IrrigationService.setCharacteristic(Characteristic.ValveType, 1); this.IrrigationService.setCharacteristic(Characteristic.SetDuration, this.timer); + this.LoggingService.getCharacteristic(LegrandMyHome.Char131) + .on('get', (callback) => { + let data = Format("0002230003021b04040c4156323248314130303036330602080007042a3000000b0200000501000204f82c00001401030f0400000000450505000000004609050000000e000042064411051c0005033c0000003a814b42a34d8c4047110594186d19071ad91ab40000003c00000048060500000000004a06050000000000d004 79010000 9b047c01 00002f0e e00f0100 00000000 00000000 2c01 2d06 0000000000001e02300c", + numToHex(swap16(this.lastEventMinus),4), + numToHex(swap16(this.lastEventPlus),4), + + + + ); + callback(null, hexToBase64(data)); + }); this.IrrigationService.getCharacteristic(Characteristic.Active) .on('set', (_value, callback) => { this.log.debug(sprintf("setIrrigation %s = %s", this.address, _value)); From 4b5a18e9d0e58266d0b0fbf3d67da86322a8a40f Mon Sep 17 00:00:00 2001 From: simont77 <26008536+simont77@users.noreply.github.com> Date: Thu, 28 Jun 2018 12:43:55 +0200 Subject: [PATCH 75/96] complete adding extra char for irrigation --- index.js | 76 ++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 55 insertions(+), 21 deletions(-) diff --git a/index.js b/index.js index 44e6ef7..a941590 100644 --- a/index.js +++ b/index.js @@ -21,6 +21,16 @@ var numToHex = function (val, len) { } return s; }; +var swap16 = function (val) { + return ((val & 0xFF) << 8) + | ((val >>> 8) & 0xFF); +}; +var swap32 = function (val) { + return ((val & 0xFF) << 24) + | ((val & 0xFF00) << 8) + | ((val >>> 8) & 0xFF00) + | ((val >>> 24) & 0xFF); +}; module.exports = function (homebridge) { Service = homebridge.hap.Service; @@ -1919,6 +1929,11 @@ class MHIrrigation { this.lastActivation = 0; this.ExtraPersistedData = {}; this.firstGet = true; + this.data131 = ""; + this.waterFlux = 1000; + this.totalWaterAmount = 0; + this.currentWaterAmount = 0; + this.timeOpening = 0; } getServices() { @@ -1931,8 +1946,6 @@ class MHIrrigation { this.IrrigationService = new Service.Valve(this.name); - - this.IrrigationService.addCharacteristic(LegrandMyHome.LastActivation); if (this.config.storage == 'fs') this.LoggingService = new LegrandMyHome.FakeGatoHistoryService("aqua", this, { storage: 'fs', disableTimer: true }); else @@ -1940,23 +1953,44 @@ class MHIrrigation { this.ExtraPersistedData = this.LoggingService.getExtraPersistedData(); if (this.ExtraPersistedData != undefined) { this.lastActivation = this.ExtraPersistedData.lastActivation || 0; + this.waterFlux = this.ExtraPersistedData.waterFlux || 1000; + this.totalWaterAmount = this.ExtraPersistedData.totalWaterAmount || 0; } - + this.LoggingService.addCharacteristic(LegrandMyHome.Char11D); this.LoggingService.addCharacteristic(LegrandMyHome.Char131); - //this.LoggingService.setCharacteristic(LegrandMyHome.Char131,hexToBase64('0002230003021b04040c4156323248314130303036330602080007042a3000000b0200000501000204f82c00001401030f0400000000450505000000004609050000000e000042064411051c0005033c0000003a814b42a34d8c4047110594186d19071ad91ab40000003c00000048060500000000004a06050000000000d004 79010000 9b047c01 00002f0e e00f0100 00000000 00000000 2c01 2d06 0000000000001e02300c')); this.IrrigationService.setCharacteristic(Characteristic.ValveType, 1); this.IrrigationService.setCharacteristic(Characteristic.SetDuration, this.timer); this.LoggingService.getCharacteristic(LegrandMyHome.Char131) .on('get', (callback) => { - let data = Format("0002230003021b04040c4156323248314130303036330602080007042a3000000b0200000501000204f82c00001401030f0400000000450505000000004609050000000e000042064411051c0005033c0000003a814b42a34d8c4047110594186d19071ad91ab40000003c00000048060500000000004a06050000000000d004 79010000 9b047c01 00002f0e e00f0100 00000000 00000000 2c01 2d06 0000000000001e02300c", - numToHex(swap16(this.lastEventMinus),4), - numToHex(swap16(this.lastEventPlus),4), - - - + this.ExtraPersistedData = this.LoggingService.getExtraPersistedData(); + if (this.ExtraPersistedData != undefined) { + this.lastActivation = this.ExtraPersistedData.lastActivation || 0; + this.waterFlux = this.ExtraPersistedData.waterFlux || 1000; + this.totalWaterAmount = this.ExtraPersistedData.totalWaterAmount || 0; + } + this.data131 = Format("0002230003021b04040c4156323248314130303036330602080007042a3000000b0200000501000204f82c00001401030f0400000000450505000000004609050000000e000042064411051c0005033c0000003a814b42a34d8c4047110594186d19071ad91ab40000003c00000048060500000000004a06050000000000d004 %s 9b04 %s 2f0e %s 00000000 00000000 %s 2d06 0000000000001e02300c", + numToHex(swap32(this.lastActivation), 8), + numToHex(swap32(moment().unit() - this.LoggingService.getInitialTime()), 8), + numToHex(swap32(this.totalWaterAmount), 8). + numToHex(swap16(this.waterFlux), 4) ); - callback(null, hexToBase64(data)); + this.log.debug("Data 131 %s: %s", this.accessoryName, this.data131); + callback(null, hexToBase64(this.data131)); + }); + this.LoggingService.getCharacteristic(LegrandMyHome.Char11D) + .on('set', (_value, callback) => { + var valHex = base64ToHex(_value); + this.log.debug("Data 11D %s: %s", this.accessoryName, valHex); + var substringCommand = valHex.substring(0, 4); + if (substringCommand == "2e02") { + var substringFlux = valHex.substring(4); + var valFluxInt = parseInt(substringFlux, 16); + this.waterFlux = swap16(valFluxInt); + } + this.LoggingService.setExtraPersistedData({ lastActivation: this.lastActivation, flux: this.waterFlux, totalWaterAmount: this.totalWaterAmount }); + this.log.debug("New flux %s: %s", this.accessoryName, this.waterFlux); + callback(null); }); this.IrrigationService.getCharacteristic(Characteristic.Active) .on('set', (_value, callback) => { @@ -1988,16 +2022,24 @@ class MHIrrigation { setTimeout(function () { this.mh.getRelayDuration(this.address); }.bind(this), 1000); + this.timeOpening = moment().unix(); } else { clearInterval(this.timerHandle); + if (moment().unix() - this.timeOpening > 0) { + this.currentWaterAmount = (moment().unix() - this.timeOpening) * this.waterFlux / 60; + this.totalWaterAmount += this.currentWaterAmount; + } + else + this.currentWaterAmount = 0; this.RemDuration = 0; this.IrrigationService.setCharacteristic(Characteristic.RemainingDuration, this.RemDuration); } this.log.debug(sprintf("changeIrrigation %s = %s", this.address, this.power)); this.lastActivation = moment().unix() - this.LoggingService.getInitialTime(); - this.LoggingService.setExtraPersistedData({ lastActivation: this.lastActivation }); - this.LoggingService.addEntry({ time: moment().unix(), status: this.power, waterAmount:1000 }); + + this.LoggingService.setExtraPersistedData({ lastActivation: this.lastActivation, flux: this.waterFlux, totalWaterAmount: this.totalWaterAmount }); + this.LoggingService.addEntry({ time: moment().unix(), status: this.power, waterAmount: this.currentWaterAmount }); }); this.IrrigationService.getCharacteristic(Characteristic.SetDuration) .on('set', (time, callback) => { @@ -2015,14 +2057,6 @@ class MHIrrigation { .on('get', (callback) => { callback(null, this.RemDuration); }); - this.IrrigationService.getCharacteristic(LegrandMyHome.LastActivation) - .on('get', (callback) => { - this.ExtraPersistedData = this.LoggingService.getExtraPersistedData(); - if (this.ExtraPersistedData != undefined) - this.lastActivation = this.ExtraPersistedData.lastActivation; - this.log.debug(sprintf("lastActivation = %f", this.lastActivation)); - callback(null, this.lastActivation); - }); return [service, this.IrrigationService, this.LoggingService]; } From 6f20c5bd65afdd2e66022b2f3037c12edd63f630 Mon Sep 17 00:00:00 2001 From: simont77 <26008536+simont77@users.noreply.github.com> Date: Wed, 4 Jul 2018 08:39:29 +0200 Subject: [PATCH 76/96] fix typos --- index.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/index.js b/index.js index a941590..7ba5e04 100644 --- a/index.js +++ b/index.js @@ -1971,9 +1971,9 @@ class MHIrrigation { } this.data131 = Format("0002230003021b04040c4156323248314130303036330602080007042a3000000b0200000501000204f82c00001401030f0400000000450505000000004609050000000e000042064411051c0005033c0000003a814b42a34d8c4047110594186d19071ad91ab40000003c00000048060500000000004a06050000000000d004 %s 9b04 %s 2f0e %s 00000000 00000000 %s 2d06 0000000000001e02300c", numToHex(swap32(this.lastActivation), 8), - numToHex(swap32(moment().unit() - this.LoggingService.getInitialTime()), 8), - numToHex(swap32(this.totalWaterAmount), 8). - numToHex(swap16(this.waterFlux), 4) + numToHex(swap32(moment().unix() - this.LoggingService.getInitialTime()), 8), + numToHex(swap32(this.totalWaterAmount), 8), + numToHex(swap16(this.waterFlux), 4) ); this.log.debug("Data 131 %s: %s", this.accessoryName, this.data131); callback(null, hexToBase64(this.data131)); From efc545624a6f224c91dd3bbed37c6280953f0748 Mon Sep 17 00:00:00 2001 From: simont77 <26008536+simont77@users.noreply.github.com> Date: Wed, 4 Jul 2018 22:05:02 +0200 Subject: [PATCH 77/96] fix for waterFlux --- index.js | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/index.js b/index.js index 7ba5e04..bb810ae 100644 --- a/index.js +++ b/index.js @@ -11,6 +11,11 @@ const Format = require('util').format; var hexToBase64 = function (val) { return new Buffer(('' + val).replace(/[^0-9A-F]/ig, ''), 'hex').toString('base64'); }; +var base64ToHex = function (val) { + if (!val) + return val; + return new Buffer(val, 'base64').toString('hex'); +}; var numToHex = function (val, len) { var s = Number(val >>> 0).toString(16); if (s.length % 2 != 0) { @@ -1975,21 +1980,22 @@ class MHIrrigation { numToHex(swap32(this.totalWaterAmount), 8), numToHex(swap16(this.waterFlux), 4) ); - this.log.debug("Data 131 %s: %s", this.accessoryName, this.data131); + this.log.debug("Data 131 %s: %s", this.name, this.data131); callback(null, hexToBase64(this.data131)); }); this.LoggingService.getCharacteristic(LegrandMyHome.Char11D) .on('set', (_value, callback) => { var valHex = base64ToHex(_value); - this.log.debug("Data 11D %s: %s", this.accessoryName, valHex); + this.log.debug("Data 11D %s: %s", this.name, valHex); var substringCommand = valHex.substring(0, 4); if (substringCommand == "2e02") { var substringFlux = valHex.substring(4); var valFluxInt = parseInt(substringFlux, 16); this.waterFlux = swap16(valFluxInt); } - this.LoggingService.setExtraPersistedData({ lastActivation: this.lastActivation, flux: this.waterFlux, totalWaterAmount: this.totalWaterAmount }); - this.log.debug("New flux %s: %s", this.accessoryName, this.waterFlux); + this.LoggingService.setExtraPersistedData({ lastActivation: this.lastActivation, waterFlux: this.waterFlux, totalWaterAmount: this.totalWaterAmount }); + this.LoggingService.addEntry({ time: moment().unix(), status: this.power }); + this.log.debug("New flux %s: %s", this.name, this.waterFlux); callback(null); }); this.IrrigationService.getCharacteristic(Characteristic.Active) @@ -2027,7 +2033,7 @@ class MHIrrigation { else { clearInterval(this.timerHandle); if (moment().unix() - this.timeOpening > 0) { - this.currentWaterAmount = (moment().unix() - this.timeOpening) * this.waterFlux / 60; + this.currentWaterAmount = (moment().unix() - this.timeOpening) * this.waterFlux; this.totalWaterAmount += this.currentWaterAmount; } else @@ -2038,7 +2044,7 @@ class MHIrrigation { this.log.debug(sprintf("changeIrrigation %s = %s", this.address, this.power)); this.lastActivation = moment().unix() - this.LoggingService.getInitialTime(); - this.LoggingService.setExtraPersistedData({ lastActivation: this.lastActivation, flux: this.waterFlux, totalWaterAmount: this.totalWaterAmount }); + this.LoggingService.setExtraPersistedData({ lastActivation: this.lastActivation, waterFlux: this.waterFlux, totalWaterAmount: this.totalWaterAmount }); this.LoggingService.addEntry({ time: moment().unix(), status: this.power, waterAmount: this.currentWaterAmount }); }); this.IrrigationService.getCharacteristic(Characteristic.SetDuration) From 7eb6829dd61a175a01ad1e1ae8e5a1051c7b9a14 Mon Sep 17 00:00:00 2001 From: simont77 <26008536+simont77@users.noreply.github.com> Date: Fri, 6 Jul 2018 10:17:53 +0200 Subject: [PATCH 78/96] update package.json --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6465fc8..09b2f70 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,6 @@ "sprintf-js": "^1.0.3", "moment": "^2.18.1", "correcting-interval": "^2.0.0", - "fakegato-history": "^0.5.1" + "fakegato-history": "^0.5.2" } } From b247934a0339a421f4c47b5c780033e7bd38f0d4 Mon Sep 17 00:00:00 2001 From: simont77 <26008536+simont77@users.noreply.github.com> Date: Fri, 6 Jul 2018 14:52:16 +0200 Subject: [PATCH 79/96] fix to avoid multiple timer creation in MHIrragation --- index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index bb810ae..2a820b6 100644 --- a/index.js +++ b/index.js @@ -380,6 +380,8 @@ class LegrandMyHome { if (accessory.address == _address && accessory.IrrigationService !== undefined) { if (accessory.power) { accessory.RemDuration = _value; + if (accessory.timerHandle != undefined) + clearInterval(accessory.timerHandle); accessory.timerHandle = setInterval(function () { accessory.IrrigationService.setCharacteristic(Characteristic.RemainingDuration, accessory.RemDuration); accessory.RemDuration--; @@ -387,8 +389,6 @@ class LegrandMyHome { clearInterval(accessory.timerHandle); }.bind(this), 1000); } - - } }.bind(this)); } From a81dc5d8a82f1bfe67743fa41a085e292715066f Mon Sep 17 00:00:00 2001 From: simont77 <26008536+simont77@users.noreply.github.com> Date: Wed, 11 Jul 2018 13:13:47 +0200 Subject: [PATCH 80/96] 0.1.13 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 09b2f70..52318b8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-myhome-tng", - "version": "0.1.12", + "version": "0.1.13", "description": "Legrand MyHome plugin for homebridge: https://github.com/nfarina/homebridge", "license": "MIT", "keywords": [ From 70cbb3e7ff63e3964ebeee7761e2e2486607e0b5 Mon Sep 17 00:00:00 2001 From: simont77 <26008536+simont77@users.noreply.github.com> Date: Tue, 17 Jul 2018 12:18:15 +0200 Subject: [PATCH 81/96] fix to improve reliability of reading of extra data from persistent storage when network is not ready --- index.js | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/index.js b/index.js index 2a820b6..2d8a7c9 100644 --- a/index.js +++ b/index.js @@ -1588,9 +1588,18 @@ class MHDryContact { this.dryContactService.getCharacteristic(Characteristic.ContactSensorState) .on('change', () => { this.log.debug(sprintf("changeContactSensorState %s = %s", this.address, this.state)); + this.ExtraPersistedData = this.LoggingService.getExtraPersistedData(); + if (this.ExtraPersistedData != undefined && this.ExtraPersistedData.lastReset != undefined) + { + this.lastReset = this.ExtraPersistedData.lastReset || 0; + } + if (this.ExtraPersistedData != undefined && this.ExtraPersistedData.numberOpened != undefined) + { + this.numberOpened = this.ExtraPersistedData.numberOpened; + } this.lastOpening = moment().unix() - this.LoggingService.getInitialTime(); if (this.state) { - this.ExtraPersistedData = this.LoggingService.getExtraPersistedData(); + if (this.ExtraPersistedData != undefined && this.ExtraPersistedData.numberOpened != undefined) this.numberOpened = this.ExtraPersistedData.numberOpened + 1; else @@ -1601,6 +1610,11 @@ class MHDryContact { }); this.dryContactService.getCharacteristic(LegrandMyHome.ResetTotal) .on('set', (value, callback) => { + this.ExtraPersistedData = this.LoggingService.getExtraPersistedData(); + if (this.ExtraPersistedData != undefined && this.ExtraPersistedData.lastOpening != undefined) + { + this.lastOpening = this.ExtraPersistedData.lastOpening; + } this.numberOpened = 0; this.lastReset = value; this.LoggingService.setExtraPersistedData({ numberOpened: this.numberOpened, lastOpening: this.lastOpening, lastReset: this.lastReset }); @@ -1988,11 +2002,18 @@ class MHIrrigation { var valHex = base64ToHex(_value); this.log.debug("Data 11D %s: %s", this.name, valHex); var substringCommand = valHex.substring(0, 4); + this.ExtraPersistedData = this.LoggingService.getExtraPersistedData(); + if (this.ExtraPersistedData != undefined) { + this.lastActivation = this.ExtraPersistedData.lastActivation || 0; + this.waterFlux = this.ExtraPersistedData.waterFlux || 1000; + this.totalWaterAmount = this.ExtraPersistedData.totalWaterAmount || 0; + } if (substringCommand == "2e02") { var substringFlux = valHex.substring(4); var valFluxInt = parseInt(substringFlux, 16); this.waterFlux = swap16(valFluxInt); } + this.LoggingService.setExtraPersistedData({ lastActivation: this.lastActivation, waterFlux: this.waterFlux, totalWaterAmount: this.totalWaterAmount }); this.LoggingService.addEntry({ time: moment().unix(), status: this.power }); this.log.debug("New flux %s: %s", this.name, this.waterFlux); @@ -2024,6 +2045,12 @@ class MHIrrigation { callback(null, this.power); }) .on('change', () => { + this.ExtraPersistedData = this.LoggingService.getExtraPersistedData(); + if (this.ExtraPersistedData != undefined) { + this.lastActivation = this.ExtraPersistedData.lastActivation || 0; + this.waterFlux = this.ExtraPersistedData.waterFlux || 1000; + this.totalWaterAmount = this.ExtraPersistedData.totalWaterAmount || 0; + } if (this.power) { setTimeout(function () { this.mh.getRelayDuration(this.address); From fb17b0c33db13a0debeb7cca27f8aff46e14f4ce Mon Sep 17 00:00:00 2001 From: simont77 <26008536+simont77@users.noreply.github.com> Date: Tue, 17 Jul 2018 12:22:54 +0200 Subject: [PATCH 82/96] 0.1.14 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 52318b8..409080f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-myhome-tng", - "version": "0.1.13", + "version": "0.1.14", "description": "Legrand MyHome plugin for homebridge: https://github.com/nfarina/homebridge", "license": "MIT", "keywords": [ From d869657544fed3c69972af3273f1904b65e56451 Mon Sep 17 00:00:00 2001 From: simont77 Date: Fri, 10 Aug 2018 19:25:01 +0200 Subject: [PATCH 83/96] fix for alarm status --- lib/mhclient.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/mhclient.js b/lib/mhclient.js index 0880097..8a34ab8 100755 --- a/lib/mhclient.js +++ b/lib/mhclient.js @@ -374,7 +374,7 @@ class MyHomeClient { } //alarm status - extract = frame.match(/^\*5\*(\d+)\*0*$/); + extract = frame.match(/^\*5\*(\d+)\*\**$/); if (extract) { let value = parseInt(extract[1], 10); switch (value) { From 7eb4b65e458c1d82fc60871d4eb7c82a81aac3e1 Mon Sep 17 00:00:00 2001 From: simont77 Date: Sat, 1 Sep 2018 15:32:38 +0200 Subject: [PATCH 84/96] fix alarm status --- index.js | 13 +++++++++++-- lib/mhclient.js | 18 ++++++++++-------- 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/index.js b/index.js index 2d8a7c9..56a4802 100644 --- a/index.js +++ b/index.js @@ -594,18 +594,27 @@ class LegrandMyHome { this.devices.forEach(function (accessory) { if (accessory.alarmBatteryService !== undefined) { accessory.lowbattery = _state; - accessory.batterycharging = !_state; if (_state == 0) accessory.batterylevel = 100; else accessory.batterylevel = 0; accessory.alarmBatteryService.getCharacteristic(Characteristic.StatusLowBattery).getValue(null); accessory.alarmBatteryService.getCharacteristic(Characteristic.BatteryLevel).getValue(null); - accessory.alarmBatteryService.getCharacteristic(Characteristic.ChargingState).getValue(null); } }.bind(this)); } + + onAlarmNetwork(_state) { + this.devices.forEach(function (accessory) { + if (accessory.alarmBatteryService !== undefined) { + accessory.batterycharging = _state; + accessory.alarmBatteryService.getCharacteristic(Characteristic.ChargingState).getValue(null); + } + }.bind(this)); + + } + onControlledLoad(_address, _value) { this.devices.forEach(function (accessory) { diff --git a/lib/mhclient.js b/lib/mhclient.js index 8a34ab8..2998c26 100755 --- a/lib/mhclient.js +++ b/lib/mhclient.js @@ -378,11 +378,13 @@ class MyHomeClient { if (extract) { let value = parseInt(extract[1], 10); switch (value) { - case 0: - + case 0: //maintenance + if (this.parent != null && this.parent.onMonitor != null && typeof (this.parent.onAlarmFault) == 'function') + this.parent.onAlarmFault(1); break; - case 1: - + case 1: //active + if (this.parent != null && this.parent.onMonitor != null && typeof (this.parent.onAlarmFault) == 'function') + this.parent.onAlarmFault(0); break; case 8: //engaged if (this.parent != null && this.parent.onMonitor != null && typeof (this.parent.onAlarm) == 'function') @@ -404,12 +406,12 @@ class MyHomeClient { this.parent.onAlarmLowBattery(0); break; case 6: //no network - if (this.parent != null && this.parent.onMonitor != null && typeof (this.parent.onAlarmFault) == 'function') - this.parent.onAlarmFault(1); + if (this.parent != null && this.parent.onMonitor != null && typeof (this.parent.onAlarmNetwork) == 'function') + this.parent.onAlarmNetwork(0); break; case 7: //network ok - if (this.parent != null && this.parent.onMonitor != null && typeof (this.parent.onAlarmFault) == 'function') - this.parent.onAlarmFault(0); + if (this.parent != null && this.parent.onMonitor != null && typeof (this.parent.onAlarmNetwork) == 'function') + this.parent.onAlarmNetwork(1); break; default: } From 964763076eb76106f5670c0f9c3f237e8db855c3 Mon Sep 17 00:00:00 2001 From: simont77 <26008536+simont77@users.noreply.github.com> Date: Sun, 30 Sep 2018 15:09:38 +0200 Subject: [PATCH 85/96] initial support for reset of total water usage for aqua --- index.js | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/index.js b/index.js index 56a4802..3db9fec 100644 --- a/index.js +++ b/index.js @@ -1962,6 +1962,7 @@ class MHIrrigation { this.totalWaterAmount = 0; this.currentWaterAmount = 0; this.timeOpening = 0; + this.lastReset = 0; } getServices() { @@ -1983,10 +1984,12 @@ class MHIrrigation { this.lastActivation = this.ExtraPersistedData.lastActivation || 0; this.waterFlux = this.ExtraPersistedData.waterFlux || 1000; this.totalWaterAmount = this.ExtraPersistedData.totalWaterAmount || 0; + this.lastReset = this.ExtraPersistedData.lastReset || 0; } this.LoggingService.addCharacteristic(LegrandMyHome.Char11D); this.LoggingService.addCharacteristic(LegrandMyHome.Char131); + this.IrrigationService.addCharacteristic(LegrandMyHome.ResetTotal); this.IrrigationService.setCharacteristic(Characteristic.ValveType, 1); this.IrrigationService.setCharacteristic(Characteristic.SetDuration, this.timer); this.LoggingService.getCharacteristic(LegrandMyHome.Char131) @@ -1996,6 +1999,7 @@ class MHIrrigation { this.lastActivation = this.ExtraPersistedData.lastActivation || 0; this.waterFlux = this.ExtraPersistedData.waterFlux || 1000; this.totalWaterAmount = this.ExtraPersistedData.totalWaterAmount || 0; + this.lastReset = this.ExtraPersistedData.lastReset || 0; } this.data131 = Format("0002230003021b04040c4156323248314130303036330602080007042a3000000b0200000501000204f82c00001401030f0400000000450505000000004609050000000e000042064411051c0005033c0000003a814b42a34d8c4047110594186d19071ad91ab40000003c00000048060500000000004a06050000000000d004 %s 9b04 %s 2f0e %s 00000000 00000000 %s 2d06 0000000000001e02300c", numToHex(swap32(this.lastActivation), 8), @@ -2016,14 +2020,22 @@ class MHIrrigation { this.lastActivation = this.ExtraPersistedData.lastActivation || 0; this.waterFlux = this.ExtraPersistedData.waterFlux || 1000; this.totalWaterAmount = this.ExtraPersistedData.totalWaterAmount || 0; + this.lastReset = this.ExtraPersistedData.lastReset || 0; } - if (substringCommand == "2e02") { + if (substringCommand == "2e02") { //set waterFlux var substringFlux = valHex.substring(4); var valFluxInt = parseInt(substringFlux, 16); this.waterFlux = swap16(valFluxInt); } - this.LoggingService.setExtraPersistedData({ lastActivation: this.lastActivation, waterFlux: this.waterFlux, totalWaterAmount: this.totalWaterAmount }); + if (substringCommand == "2f04") { //reset totalizer + var substringLastReset = valHex.substring(4); + var valLastResetInt = parseInt(substringLastReset, 16); + this.lastReset = swap32(valLastResetInt); + this.totalWaterAmount = 0; + } + + this.LoggingService.setExtraPersistedData({ lastActivation: this.lastActivation, waterFlux: this.waterFlux, totalWaterAmount: this.totalWaterAmount, lastReset: this.lastReset }); this.LoggingService.addEntry({ time: moment().unix(), status: this.power }); this.log.debug("New flux %s: %s", this.name, this.waterFlux); callback(null); @@ -2059,6 +2071,7 @@ class MHIrrigation { this.lastActivation = this.ExtraPersistedData.lastActivation || 0; this.waterFlux = this.ExtraPersistedData.waterFlux || 1000; this.totalWaterAmount = this.ExtraPersistedData.totalWaterAmount || 0; + this.lastReset = this.ExtraPersistedData.lastReset || 0; } if (this.power) { setTimeout(function () { @@ -2080,7 +2093,7 @@ class MHIrrigation { this.log.debug(sprintf("changeIrrigation %s = %s", this.address, this.power)); this.lastActivation = moment().unix() - this.LoggingService.getInitialTime(); - this.LoggingService.setExtraPersistedData({ lastActivation: this.lastActivation, waterFlux: this.waterFlux, totalWaterAmount: this.totalWaterAmount }); + this.LoggingService.setExtraPersistedData({ lastActivation: this.lastActivation, waterFlux: this.waterFlux, totalWaterAmount: this.totalWaterAmount, lastReset: this.lastReset }); this.LoggingService.addEntry({ time: moment().unix(), status: this.power, waterAmount: this.currentWaterAmount }); }); this.IrrigationService.getCharacteristic(Characteristic.SetDuration) @@ -2099,6 +2112,17 @@ class MHIrrigation { .on('get', (callback) => { callback(null, this.RemDuration); }); + this.IrrigationService.getCharacteristic(LegrandMyHome.ResetTotal) + .on('get', (callback) => { + this.ExtraPersistedData = this.LoggingService.getExtraPersistedData(); + if (this.ExtraPersistedData != undefined) { + this.lastActivation = this.ExtraPersistedData.lastActivation || 0; + this.waterFlux = this.ExtraPersistedData.waterFlux || 1000; + this.totalWaterAmount = this.ExtraPersistedData.totalWaterAmount || 0; + this.lastReset = this.ExtraPersistedData.lastReset || 0; + } + callback(null, this.lastReset); + }); return [service, this.IrrigationService, this.LoggingService]; } From d6ccb492b192f5fe4e2ca8e26bfd4cd8daad0147 Mon Sep 17 00:00:00 2001 From: simont77 <26008536+simont77@users.noreply.github.com> Date: Sat, 7 Sep 2019 19:42:24 +0200 Subject: [PATCH 86/96] fix PowerMeter for Eve 3.8.1 compatibility --- index.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/index.js b/index.js index 3db9fec..ec0c7ed 100644 --- a/index.js +++ b/index.js @@ -1406,6 +1406,8 @@ class MHPowerMeter { .setCharacteristic(Characteristic.FirmwareRevision, version) .setCharacteristic(Characteristic.SerialNumber, "Name-" + this.name); + this.outlet = new Service.Outlet(this.name + " dumb switch"); + this.powerMeterService = new LegrandMyHome.PowerMeterService(this.name); this.powerMeterService.getCharacteristic(LegrandMyHome.CurrentPowerConsumption) .on('get', (callback) => { @@ -1439,7 +1441,7 @@ class MHPowerMeter { else this.powerLoggingService = new LegrandMyHome.FakeGatoHistoryService("energy", this, { storage: 'googleDrive', path: 'homebridge' }); - return [service, this.powerMeterService, this.powerLoggingService]; + return [service, this.powerMeterService, this.powerLoggingService, this.outlet]; } } From 52ab5abbfb63bf613b64265b1fb6bf9a059b5c29 Mon Sep 17 00:00:00 2001 From: simont77 <26008536+simont77@users.noreply.github.com> Date: Sat, 7 Sep 2019 19:47:25 +0200 Subject: [PATCH 87/96] 0.1.15, update fakegato dependency --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 409080f..fb507e3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-myhome-tng", - "version": "0.1.14", + "version": "0.1.15", "description": "Legrand MyHome plugin for homebridge: https://github.com/nfarina/homebridge", "license": "MIT", "keywords": [ @@ -24,6 +24,6 @@ "sprintf-js": "^1.0.3", "moment": "^2.18.1", "correcting-interval": "^2.0.0", - "fakegato-history": "^0.5.2" + "fakegato-history": "^0.5.4" } } From dd5313c4aa8ee0b3c59e84c2f28c677a1566faea Mon Sep 17 00:00:00 2001 From: simont77 <26008536+simont77@users.noreply.github.com> Date: Sun, 8 Sep 2019 11:35:42 +0200 Subject: [PATCH 88/96] fix regex for alarm status --- lib/mhclient.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/mhclient.js b/lib/mhclient.js index 2998c26..601fad2 100755 --- a/lib/mhclient.js +++ b/lib/mhclient.js @@ -374,7 +374,7 @@ class MyHomeClient { } //alarm status - extract = frame.match(/^\*5\*(\d+)\*\**$/); + extract = frame.match(/^\*5\*(\d+)\*(0*)$/); if (extract) { let value = parseInt(extract[1], 10); switch (value) { From 51412957f438163d9cd97f66b1782e9d4e3c6185 Mon Sep 17 00:00:00 2001 From: simont77 <26008536+simont77@users.noreply.github.com> Date: Sun, 8 Sep 2019 11:38:51 +0200 Subject: [PATCH 89/96] 0.1.16 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index fb507e3..514bdaa 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-myhome-tng", - "version": "0.1.15", + "version": "0.1.16", "description": "Legrand MyHome plugin for homebridge: https://github.com/nfarina/homebridge", "license": "MIT", "keywords": [ From a36516df162ca351009dcdccf5bccc6c0f4c4825 Mon Sep 17 00:00:00 2001 From: simont77 <26008536+simont77@users.noreply.github.com> Date: Thu, 16 Apr 2020 11:17:45 +0200 Subject: [PATCH 90/96] fix blind partial opening --- index.js | 47 ++++++++++++++++++++++++++++++++++------------- lib/mhclient.js | 5 +++-- 2 files changed, 37 insertions(+), 15 deletions(-) diff --git a/index.js b/index.js index ec0c7ed..a11bcdb 100644 --- a/index.js +++ b/index.js @@ -1027,6 +1027,7 @@ class MHBlind { this.bus = parseInt(address[0]); this.ambient = parseInt(address[1]); this.pl = parseInt(address[2]); + this.timer = 0; } evaluatePosition() { @@ -1038,7 +1039,8 @@ class MHBlind { if (this.runningDirection != Characteristic.PositionState.STOPPED && this.state == Characteristic.PositionState.STOPPED) { if (this.runningDirection == Characteristic.PositionState.INCREASING) { this.currentPosition = Math.min(100, this.currentPosition + (100 / (this.time * 1000) * (((new Date()) - this.runningStartTime + this.startDelayMs) * (1 + this.timeAdjust / 100)))); - } else { + } + if (this.runningDirection == Characteristic.PositionState.DECREASING) { this.currentPosition = Math.max(0, this.currentPosition - (100 / (this.time * 1000) * (((new Date()) - this.runningStartTime + this.startDelayMs) * (1 + this.timeAdjust / 100)))); } this.runningDirection = this.state; @@ -1047,7 +1049,12 @@ class MHBlind { this.log.debug(sprintf("Ending position is %d", this.currentPosition)); } else { - /* Uhm... */ + if (this.runningDirection == Characteristic.PositionState.INCREASING) { + this.currentPosition = Math.min(100, this.currentPosition + (100 / (this.time * 1000) * (((new Date()) - this.runningStartTime + this.startDelayMs) * (1 + this.timeAdjust / 100)))); + } + if (this.runningDirection == Characteristic.PositionState.DECREASING) { + this.currentPosition = Math.max(0, this.currentPosition - (100 / (this.time * 1000) * (((new Date()) - this.runningStartTime + this.startDelayMs) * (1 + this.timeAdjust / 100)))); + } } } } @@ -1076,32 +1083,46 @@ class MHBlind { this.windowCoveringService.getCharacteristic(Characteristic.CurrentPosition) .on('get', (callback) => { - this.log.debug(sprintf("getCurrentPosition %s = %s", this.address, this.state)); + this.log.debug(sprintf("getCurrentPosition %s = %s", this.address, this.currentPosition)); callback(null, this.currentPosition); }); this.windowCoveringService.getCharacteristic(Characteristic.TargetPosition) .on('set', (value, callback) => { this.targetPosition = value; + this.log.debug(sprintf("setTargetPosition %s = %s", this.address, this.targetPosition)); var travelTimeMs = this.evaluateTravelTimeMs(this.currentPosition, this.targetPosition); - if (value > this.currentPosition) { + if (value > this.currentPosition && this.state != Characteristic.PositionState.INCREASING) { this.mh.simpleBlindCommand(this.address, 1); - } else { + //this.state = Characteristic.PositionState.INCREASING; + //this.evaluatePosition(); + } else if (value < this.currentPosition && this.state != Characteristic.PositionState.DECREASING) { this.mh.simpleBlindCommand(this.address, 2); + //this.state = Characteristic.PositionState.DECREASING; + //this.evaluatePosition(); + } else { + this.mh.simpleBlindCommand(this.address, 0); + //this.state = Characteristic.PositionState.STOPPED; + //this.evaluatePosition(); } /* Use the calculated travel time only if the target isn't the complete Up or Complete Down */ - if (this.targetPosition > 0 && this.targetPosition < 100) { + if (this.targetPosition > 0 && this.targetPosition < 100 && this.currentPosition != this.targetPosition) { if (travelTimeMs > 0) { - setTimeout(function () { + clearTimeout(this.timer); + this.timer = setTimeout(function () { this.mh.simpleBlindCommand(this.address, 0); + //this.state = Characteristic.PositionState.STOPPED; + //this.evaluatePosition(); + this.log.debug(sprintf("setTargetPosition %s at %s done", this.address, this.targetPosition)); }.bind(this), travelTimeMs); } } + callback(null); }) .on('get', (callback) => { - this.log.debug(sprintf("getTargetPosition %s = %s", this.address, this.state)); + this.log.debug(sprintf("getTargetPosition %s = %s", this.address, this.targetPosition)); callback(null, this.targetPosition); }); @@ -1845,28 +1866,28 @@ class MHAlarm { }); this.alarmService.getCharacteristic(Characteristic.StatusFault) .on('get', (callback) => { - this.log.debug(sprintf("getConsumptio = %s", this.value)); + this.log.debug(sprintf("alarm status fault get = %s", this.fault)); callback(null, this.fault); }); this.alarmService.getCharacteristic(Characteristic.StatusTampered) .on('get', (callback) => { - this.log.debug(sprintf("getConsumptio = %s", this.value)); + this.log.debug(sprintf("alarm status tampered get = %s", this.tampered)); callback(null, this.tampered); }); this.alarmBatteryService = new Service.BatteryService(this.name); this.alarmBatteryService.getCharacteristic(Characteristic.StatusLowBattery) .on('get', (callback) => { - this.log.debug(sprintf("alarm current = %d", this.state)); + this.log.debug(sprintf("alarm statuslowbatery = %d", this.lowbattery)); callback(null, this.lowbattery); }); this.alarmBatteryService.getCharacteristic(Characteristic.BatteryLevel) .on('get', (callback) => { - this.log.debug(sprintf("alarm current = %d", this.state)); + this.log.debug(sprintf("alarm batterylevel = %d", this.batterylevel)); callback(null, this.batterylevel); }); this.alarmBatteryService.getCharacteristic(Characteristic.ChargingState) .on('get', (callback) => { - this.log.debug(sprintf("alarm current = %d", this.state)); + this.log.debug(sprintf("alarm batterycharging = %d", this.batterycharging)); callback(null, this.batterycharging); }); diff --git a/lib/mhclient.js b/lib/mhclient.js index 601fad2..795ae76 100755 --- a/lib/mhclient.js +++ b/lib/mhclient.js @@ -118,9 +118,10 @@ class MyHomeClient { /* Send a starting stop */ if (_stopUpDown != 0) { - this.command.send(sprintf("*2*%d*%s##", 0, address)); + this.command.send(sprintf("*2*%d*%s##", 0, address)); } - this.command.send(sprintf("*2*%d*%s##", parseInt(_stopUpDown), address)); + //this.command.send(sprintf("*2*%d*%s##", parseInt(_stopUpDown), address)); + this._bufferCommand("BLIND", address, sprintf("*2*%d*%s##", parseInt(_stopUpDown), address), 500); } advancedBlindCommand(_address, _shutterLevel) { From 75f38805a602d36902756b8b2b05113bc7ca5e96 Mon Sep 17 00:00:00 2001 From: simont77 <26008536+simont77@users.noreply.github.com> Date: Thu, 16 Apr 2020 17:42:34 +0200 Subject: [PATCH 91/96] cleanup --- index.js | 8 -------- 1 file changed, 8 deletions(-) diff --git a/index.js b/index.js index a11bcdb..577b1d7 100644 --- a/index.js +++ b/index.js @@ -1094,16 +1094,10 @@ class MHBlind { var travelTimeMs = this.evaluateTravelTimeMs(this.currentPosition, this.targetPosition); if (value > this.currentPosition && this.state != Characteristic.PositionState.INCREASING) { this.mh.simpleBlindCommand(this.address, 1); - //this.state = Characteristic.PositionState.INCREASING; - //this.evaluatePosition(); } else if (value < this.currentPosition && this.state != Characteristic.PositionState.DECREASING) { this.mh.simpleBlindCommand(this.address, 2); - //this.state = Characteristic.PositionState.DECREASING; - //this.evaluatePosition(); } else { this.mh.simpleBlindCommand(this.address, 0); - //this.state = Characteristic.PositionState.STOPPED; - //this.evaluatePosition(); } /* Use the calculated travel time only if the target isn't the complete Up or Complete Down */ @@ -1112,8 +1106,6 @@ class MHBlind { clearTimeout(this.timer); this.timer = setTimeout(function () { this.mh.simpleBlindCommand(this.address, 0); - //this.state = Characteristic.PositionState.STOPPED; - //this.evaluatePosition(); this.log.debug(sprintf("setTargetPosition %s at %s done", this.address, this.targetPosition)); }.bind(this), travelTimeMs); } From 501f838e74efe2ef0590be7d74753d5c8e463d34 Mon Sep 17 00:00:00 2001 From: simont77 <26008536+simont77@users.noreply.github.com> Date: Tue, 21 Apr 2020 17:16:47 +0200 Subject: [PATCH 92/96] fix blind timer --- index.js | 96 +++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 67 insertions(+), 29 deletions(-) diff --git a/index.js b/index.js index 577b1d7..1d62796 100644 --- a/index.js +++ b/index.js @@ -655,21 +655,27 @@ class LegrandMyHome { case 0: accessory.state = Characteristic.PositionState.STOPPED; accessory.evaluatePosition(); + clearInterval(accessory.updateTimer); break; case 1: if (accessory.invert == false) accessory.state = Characteristic.PositionState.INCREASING; else accessory.state = Characteristic.PositionState.DECREASING; - accessory.evaluatePosition(); + accessory.updateTimer = setInterval(function () { + accessory.evaluatePosition(); + accessory.windowCoveringService.getCharacteristic(Characteristic.CurrentPosition).getValue(null); + }.bind(accessory), 500); break; case 2: - if (accessory.invert == false) accessory.state = Characteristic.PositionState.DECREASING; else accessory.state = Characteristic.PositionState.INCREASING; - accessory.evaluatePosition(); + accessory.updateTimer = setInterval(function () { + accessory.evaluatePosition(); + accessory.windowCoveringService.getCharacteristic(Characteristic.CurrentPosition).getValue(null); + }.bind(accessory), 500); break; } accessory.windowCoveringService.getCharacteristic(Characteristic.PositionState).getValue(null); @@ -685,20 +691,27 @@ class LegrandMyHome { case 0: accessory.state = Characteristic.PositionState.STOPPED; accessory.evaluatePosition(); + clearInterval(accessory.updateTimer); break; case 1: if (accessory.invert == false) accessory.state = Characteristic.PositionState.INCREASING; else accessory.state = Characteristic.PositionState.DECREASING; - accessory.evaluatePosition(); + accessory.updateTimer = setInterval(function () { + accessory.evaluatePosition(); + accessory.windowCoveringService.getCharacteristic(Characteristic.CurrentPosition).getValue(null); + }.bind(accessory), 500); break; case 2: if (accessory.invert == false) accessory.state = Characteristic.PositionState.DECREASING; else accessory.state = Characteristic.PositionState.INCREASING; - accessory.evaluatePosition(); + accessory.updateTimer = setInterval(function () { + accessory.evaluatePosition(); + accessory.windowCoveringService.getCharacteristic(Characteristic.CurrentPosition).getValue(null); + }.bind(accessory), 500); break; } accessory.windowCoveringService.getCharacteristic(Characteristic.PositionState).getValue(null); @@ -713,20 +726,27 @@ class LegrandMyHome { case 0: accessory.state = Characteristic.PositionState.STOPPED; accessory.evaluatePosition(); + clearInterval(accessory.updateTimer); break; case 1: if (accessory.invert == false) accessory.state = Characteristic.PositionState.INCREASING; else accessory.state = Characteristic.PositionState.DECREASING; - accessory.evaluatePosition(); + accessory.updateTimer = setInterval(function () { + accessory.evaluatePosition(); + accessory.windowCoveringService.getCharacteristic(Characteristic.CurrentPosition).getValue(null); + }.bind(accessory), 500); break; case 2: if (accessory.invert == false) accessory.state = Characteristic.PositionState.DECREASING; else accessory.state = Characteristic.PositionState.INCREASING; - accessory.evaluatePosition(); + accessory.updateTimer = setInterval(function () { + accessory.evaluatePosition(); + accessory.windowCoveringService.getCharacteristic(Characteristic.CurrentPosition).getValue(null); + }.bind(accessory), 500); break; } accessory.windowCoveringService.getCharacteristic(Characteristic.PositionState).getValue(null); @@ -1015,12 +1035,13 @@ class MHBlind { this.invert = config.invert || false; this.runningStartTime = -1; + this.startPosition = 0; this.runningDirection = Characteristic.PositionState.STOPPED; this.state = Characteristic.PositionState.STOPPED; this.currentPosition = 0; this.targetPosition = 0; this.startDelayMs = config.startDelayMs || 0; /* Start delay of the automation and MH relay */ - this.timeAdjust = config.timeAdjust || 5; /* Percent error, F411 is a bit buggy */ + this.timeAdjust = config.timeAdjust || 0; /* Percent error, F411 is a bit buggy */ this.log.info(sprintf("LegrandMyHome::MHBlind create object: %s", this.address)); var address = this.address.split("/"); @@ -1028,32 +1049,44 @@ class MHBlind { this.ambient = parseInt(address[1]); this.pl = parseInt(address[2]); this.timer = 0; + this.updateTimer = 0; + this.travelTimeMs = -1; } evaluatePosition() { if (this.runningDirection == Characteristic.PositionState.STOPPED && this.state != Characteristic.PositionState.STOPPED) { this.runningStartTime = new Date(); + this.startPosition = this.currentPosition; this.runningDirection = this.state; this.log.debug(sprintf("Starting position is %d", this.currentPosition)); + /* Use the calculated travel time only if the target isn't the complete Up or Complete Down */ + if (this.travelTimeMs > 0) { + clearTimeout(this.timer); + this.timer = setTimeout(function () { + this.mh.simpleBlindCommand(this.address, 0); + this.log.debug(sprintf("setTargetPosition %s at %s done", this.address, this.targetPosition)); + }.bind(this), this.travelTimeMs); + } } else { if (this.runningDirection != Characteristic.PositionState.STOPPED && this.state == Characteristic.PositionState.STOPPED) { if (this.runningDirection == Characteristic.PositionState.INCREASING) { - this.currentPosition = Math.min(100, this.currentPosition + (100 / (this.time * 1000) * (((new Date()) - this.runningStartTime + this.startDelayMs) * (1 + this.timeAdjust / 100)))); + this.currentPosition = Math.min(100, this.startPosition + (100 / (this.time * 1000) * (((new Date()) - this.runningStartTime + this.startDelayMs) * (1 + this.timeAdjust / 100)))); } if (this.runningDirection == Characteristic.PositionState.DECREASING) { - this.currentPosition = Math.max(0, this.currentPosition - (100 / (this.time * 1000) * (((new Date()) - this.runningStartTime + this.startDelayMs) * (1 + this.timeAdjust / 100)))); + this.currentPosition = Math.max(0, this.startPosition - (100 / (this.time * 1000) * (((new Date()) - this.runningStartTime + this.startDelayMs) * (1 + this.timeAdjust / 100)))); } this.runningDirection = this.state; this.targetPosition = this.currentPosition; this.runningStartTime = -1; + this.travelTimeMs = -1; this.log.debug(sprintf("Ending position is %d", this.currentPosition)); } else { if (this.runningDirection == Characteristic.PositionState.INCREASING) { - this.currentPosition = Math.min(100, this.currentPosition + (100 / (this.time * 1000) * (((new Date()) - this.runningStartTime + this.startDelayMs) * (1 + this.timeAdjust / 100)))); + this.currentPosition = Math.min(100, this.startPosition + (100 / (this.time * 1000) * (((new Date()) - this.runningStartTime + this.startDelayMs) * (1 + this.timeAdjust / 100)))); } if (this.runningDirection == Characteristic.PositionState.DECREASING) { - this.currentPosition = Math.max(0, this.currentPosition - (100 / (this.time * 1000) * (((new Date()) - this.runningStartTime + this.startDelayMs) * (1 + this.timeAdjust / 100)))); + this.currentPosition = Math.max(0, this.startPosition - (100 / (this.time * 1000) * (((new Date()) - this.runningStartTime + this.startDelayMs) * (1 + this.timeAdjust / 100)))); } } } @@ -1091,25 +1124,30 @@ class MHBlind { .on('set', (value, callback) => { this.targetPosition = value; this.log.debug(sprintf("setTargetPosition %s = %s", this.address, this.targetPosition)); - var travelTimeMs = this.evaluateTravelTimeMs(this.currentPosition, this.targetPosition); - if (value > this.currentPosition && this.state != Characteristic.PositionState.INCREASING) { - this.mh.simpleBlindCommand(this.address, 1); - } else if (value < this.currentPosition && this.state != Characteristic.PositionState.DECREASING) { - this.mh.simpleBlindCommand(this.address, 2); - } else { - this.mh.simpleBlindCommand(this.address, 0); - } + + + if (this.invert == false) + if (value > this.currentPosition && this.state != Characteristic.PositionState.INCREASING) { + this.mh.simpleBlindCommand(this.address, 1); + } else if (value < this.currentPosition && this.state != Characteristic.PositionState.DECREASING) { + this.mh.simpleBlindCommand(this.address, 2); + } else { + this.mh.simpleBlindCommand(this.address, 0); + } + else + if (value > this.currentPosition && this.state != Characteristic.PositionState.INCREASING) { + this.mh.simpleBlindCommand(this.address, 2); + } else if (value < this.currentPosition && this.state != Characteristic.PositionState.DECREASING) { + this.mh.simpleBlindCommand(this.address, 1); + } else { + this.mh.simpleBlindCommand(this.address, 0); + } /* Use the calculated travel time only if the target isn't the complete Up or Complete Down */ - if (this.targetPosition > 0 && this.targetPosition < 100 && this.currentPosition != this.targetPosition) { - if (travelTimeMs > 0) { - clearTimeout(this.timer); - this.timer = setTimeout(function () { - this.mh.simpleBlindCommand(this.address, 0); - this.log.debug(sprintf("setTargetPosition %s at %s done", this.address, this.targetPosition)); - }.bind(this), travelTimeMs); - } - } + if (this.targetPosition > 0 && this.targetPosition < 100 && this.currentPosition != this.targetPosition) + this.travelTimeMs = this.evaluateTravelTimeMs(this.currentPosition, this.targetPosition); + else + this.travelTimeMs = -1; callback(null); }) From a86bb2ba8aef46f24b0c4b40b679ced0210df766 Mon Sep 17 00:00:00 2001 From: simont77 <26008536+simont77@users.noreply.github.com> Date: Tue, 21 Apr 2020 17:27:54 +0200 Subject: [PATCH 93/96] 0.1.17 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 514bdaa..c3b2884 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-myhome-tng", - "version": "0.1.16", + "version": "0.1.17", "description": "Legrand MyHome plugin for homebridge: https://github.com/nfarina/homebridge", "license": "MIT", "keywords": [ From d9f775c832c919d463c0e16ec17ce2cc18449dee Mon Sep 17 00:00:00 2001 From: simont77 <26008536+simont77@users.noreply.github.com> Date: Thu, 30 Apr 2020 12:22:40 +0200 Subject: [PATCH 94/96] update depencencies --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index c3b2884..3465510 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "homebridge-myhome-tng", + "name": "homebridge-myhome", "version": "0.1.17", "description": "Legrand MyHome plugin for homebridge: https://github.com/nfarina/homebridge", "license": "MIT", @@ -24,6 +24,6 @@ "sprintf-js": "^1.0.3", "moment": "^2.18.1", "correcting-interval": "^2.0.0", - "fakegato-history": "^0.5.4" + "fakegato-history": "^0.5.6" } } From 7b32ffb70caf77c1cd34730fb209bc8a3cd01b7e Mon Sep 17 00:00:00 2001 From: simont77 <26008536+simont77@users.noreply.github.com> Date: Thu, 30 Apr 2020 12:22:55 +0200 Subject: [PATCH 95/96] 0.1.18 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 3465510..8408b6b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-myhome", - "version": "0.1.17", + "version": "0.1.18", "description": "Legrand MyHome plugin for homebridge: https://github.com/nfarina/homebridge", "license": "MIT", "keywords": [ From 6745ec78f9046f51263ad86d854641f6e39781d4 Mon Sep 17 00:00:00 2001 From: simont77 <26008536+simont77@users.noreply.github.com> Date: Thu, 17 Nov 2022 10:13:56 +0100 Subject: [PATCH 96/96] update fakegato dep --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 8408b6b..6a9bffc 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homebridge-myhome", - "version": "0.1.18", + "version": "0.1.19", "description": "Legrand MyHome plugin for homebridge: https://github.com/nfarina/homebridge", "license": "MIT", "keywords": [ @@ -24,6 +24,6 @@ "sprintf-js": "^1.0.3", "moment": "^2.18.1", "correcting-interval": "^2.0.0", - "fakegato-history": "^0.5.6" + "fakegato-history": "^0.6.3" } }