diff --git a/README.md b/README.md index 70bc143..48ca8e5 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,17 @@ # Homebridge Pi Garage Door Opener With Sensor -This is a [homebridge](https://github.com/nfarina/homebridge) plugin to make a Raspberry Pi connected with a Relay Board into a Garage Door Opener, via the Home app on iOS using Homekit. It uses a magnetic switch to determine the state of the garage door, open or closed. Tested with iOS 11. +This is a [homebridge](https://github.com/nfarina/homebridge) plugin to make a Raspberry Pi connected with a Relay Board into a Garage Door Opener, via the Home app on iOS using Homekit. It uses a magnetic switch to determine the state of the garage door, open or closed. The wires from the Relay go into the same ports as the wired button for the garage door. When the Relay closes the circuit it acts like the button was pushed. Tested with iOS 13. -Homebridge works best I have found when run in sudo. + +### Start on boot + +Have the "homebridge" command run at boot. ### Sample Config -Config to be placed in .homebridge/config.json -* If you run homebridge from sudo, place config in /root/.homebridge/config.json -* If you run homebridge without sudo, place config in /home/pi/.homebridge/config.json +Rename config.sample.json to config.json and place in .homebridge/config.json ```json { @@ -28,7 +29,10 @@ Config to be placed in .homebridge/config.json "accessory": "Garage Door Opener", "name": "Garage Door", "doorRelayPin": 11, - "doorSensorPin": 10 + "doorSensorPin": 16, + "invertDoorState": false, + "invertSensorState": false, + "duration_ms": 500 //number of milliseconds relay will close the circuit }] } ``` @@ -36,13 +40,14 @@ Config to be placed in .homebridge/config.json ### How to Setup ``` -sudo apt-get install libavahi-compat-libdnssd-dev -git clone git://github.com/quick2wire/quick2wire-gpio-admin.git -cd quick2wire-gpio-admin -make -sudo make install -sudo adduser $USER gpio sudo npm install -g --unsafe-perm homebridge sudo npm install -g homebridge-garage-door-wsensor -sudo homebridge +``` +Rename config.sample.json to config.json and place in .homebridge/config.json + + +### How to Start +Run the following command +``` +homebridge ``` \ No newline at end of file diff --git a/config.sample.json b/config.sample.json index cce67a5..a8d7249 100644 --- a/config.sample.json +++ b/config.sample.json @@ -1,7 +1,7 @@ { "bridge": { "name": "Garage Homebridge", - "username": "CC:22:3D:E3:CE:30", + "username": "CC:22:3D:E3:CE:34", "port": 51826, "pin":"031-45-154", "manufacturer": "@nfarina", @@ -13,6 +13,9 @@ "accessory": "Garage Door Opener", "name": "Garage Door", "doorRelayPin": 11, - "doorSensorPin": 10 + "doorSensorPin": 16, + "invertDoorState": false, + "invertSensorState": false, + "duration_ms": 500 }] } \ No newline at end of file diff --git a/index.js b/index.js index 460cef2..4b34d07 100644 --- a/index.js +++ b/index.js @@ -1,116 +1,119 @@ -var gpio = require('pi-gpio'); -let Service, Characteristic, TargetDoorState, CurrentDoorState; -const OFF = true; -const ON = false; - -module.exports = function(homebridge) { - Service = homebridge.hap.Service; - Characteristic = homebridge.hap.Characteristic; - TargetDoorState = Characteristic.TargetDoorState; - CurrentDoorState = Characteristic.CurrentDoorState; - DoorState = homebridge.hap.Characteristic.CurrentDoorState; - homebridge.registerAccessory('homebridge-garage-door-opener', 'Garage Door Opener', GarageDoorOpener); -}; - -class GarageDoorOpener { - constructor(log, config) { +var Service, Characteristic, TargetDoorState, CurrentDoorState; +var rpio = require('rpio'); + +module.exports = function (homebridge) { + Service = homebridge.hap.Service; + Characteristic = homebridge.hap.Characteristic; + TargetDoorState = Characteristic.TargetDoorState; + CurrentDoorState = Characteristic.CurrentDoorState; + DoorState = homebridge.hap.Characteristic.CurrentDoorState; + homebridge.registerAccessory('homebridge-garage-door-wsensor', 'Garage Door Opener', GarageDoorOpener); +} + +function GarageDoorOpener(log, config) { this.log = log; this.name = config.name; this.doorRelayPin = config.doorRelayPin; this.doorSensorPin = config.doorSensorPin; - this.checkSensor(); this.currentDoorState = CurrentDoorState.CLOSED; this.targetDoorState = TargetDoorState.CLOSED; - this.DoorState = 1; - this.pinChange = 0; - } - - identify(callback) { - this.log('Identify requested!'); - callback(null); - } - - openCloseGarage(callback) { - var self = this; - gpio.open(self.doorRelayPin, 'output', function() { - gpio.write(self.doorRelayPin, 1, function() { - // SET VALUE 1 TO SET RELAY HIGH - }); - }); - setTimeout(() => { - gpio.open(self.doorRelayPin, 'output', function() { - gpio.write(self.doorRelayPin, 0, function() { - // SET VALUE 0 TO SET RELAY LOW - }); - }); - }, 700); - } - - checkSensor(){ - var self = this; - setTimeout(function(){ - gpio.open(self.doorSensorPin, 'input', function() { - gpio.read(self.doorSensorPin, function(gself,value) { - if(value === 1){ - if(self.DoorState != value){ - self.pinChange = 1; - self.service.setCharacteristic(TargetDoorState, TargetDoorState.OPEN); - } - self.pinChange = 0; - self.service.setCharacteristic(CurrentDoorState, CurrentDoorState.OPEN); - self.targetDoorState = 0; - } else { - if(self.DoorState != value){ - self.pinChange = 1; - self.service.setCharacteristic(TargetDoorState, TargetDoorState.CLOSED); - } - self.pinChange = 0; - self.service.setCharacteristic(CurrentDoorState, CurrentDoorState.CLOSED); - self.targetDoorState = 1; - } - self.DoorState = value; - self.checkSensor(); - }); - }); - },500); - } - - getServices() { - const informationService = new Service.AccessoryInformation(); - - informationService - .setCharacteristic(Characteristic.Manufacturer, 'Encore Dev Labs') - .setCharacteristic(Characteristic.Model, 'Kraft Garage Door Opener') - .setCharacteristic(Characteristic.SerialNumber, 'Raspberry Pi'); + this.invertDoorState = defaultVal(config["invertDoorState"], false); + this.invertSensorState = defaultVal(config['invertSensorState'], false); + this.default = defaultVal(config["default_state"], false); + this.duration = defaultVal(config["duration_ms"], 0); + this.doorState = 0; + this.sensorChange = 0; + this.service = null; + + if (!this.doorRelayPin) throw new Error("You must provide a config value for 'doorRelayPin'."); + if (!this.doorSensorPin) throw new Error("You must provide a config value for 'doorSensorPin'."); + if (!is_int(this.duration)) throw new Error("The config value 'duration' must be an integer number of milliseconds."); + this.log("Creating a garage door relay named '%s', initial state: %s", this.name, (this.invertDoorState ? "OPEN" : "CLOSED")); + rpio.open(this.doorRelayPin, rpio.OUTPUT, this.gpioDoorVal(this.invertDoorState)); + rpio.open(this.doorSensorPin, rpio.OUTPUT, this.gpioSensorVal(this.invertSensorState)); + this.checkSensor(e => {}); +} + +GarageDoorOpener.prototype.getServices = function () { this.service = new Service.GarageDoorOpener(this.name, this.name); this.service.setCharacteristic(TargetDoorState, TargetDoorState.CLOSED); - this.service.setCharacteristic(CurrentDoorState, CurrentDoorState.CLOSED); - - this.service.getCharacteristic(TargetDoorState) - .on('get', (callback) => { - callback(null, this.targetDoorState); - }) - .on('set', (value, callback) => { - this.targetDoorState = value; - if (this.targetDoorState === TargetDoorState.OPEN) { - if(this.pinChange == 0 ){ - this.openCloseGarage(); - } - } else if (this.targetDoorState === TargetDoorState.CLOSED) { - if(this.pinChange == 0 ){ - this.openCloseGarage(); - } - } - this.pinChange = 0; - callback(); - }); - this.service - .getCharacteristic(Characteristic.Name) - .on('get', callback => { - callback(null, this.name); - }); - - return [informationService, this.service]; - } + this.service.setCharacteristic(CurrentDoorState, CurrentDoorState.CLOSED); + this.service.getCharacteristic(CurrentDoorState) + .on('get', this.getSensorStatus.bind(this)) + this.service.getCharacteristic(TargetDoorState) + .on('get', this.getSensorStatus.bind(this)) + .on('set', this.setDoorOpen.bind(this)); + return [this.service]; +} + +GarageDoorOpener.prototype.getSensorStatus = function (callback) { + callback(null, this.readSensorState()); } + +GarageDoorOpener.prototype.checkSensor = function (callback) { + setTimeout(e => { + this.doorState = this.readSensorState(); + if (this.doorState !== this.sensorChange){ + this.service.getCharacteristic(TargetDoorState).updateValue(this.doorState); + this.service.getCharacteristic(CurrentDoorState).updateValue(this.doorState); + this.sensorChange = this.doorState; + } + this.checkSensor(callback); + }, 500); + + callback(null); +} + +GarageDoorOpener.prototype.readSensorState = function () { + var val = this.gpioSensorVal(rpio.read(this.doorSensorPin)); + console.log('readSensorState: ' + val); + return val == rpio.HIGH; +} + +GarageDoorOpener.prototype.setState = function (val) { + rpio.write(this.doorRelayPin, this.gpioDoorVal(val)); +} + +GarageDoorOpener.prototype.setDoorOpen = function (newState, callback) { + console.log('setDoorOpen: ' + newState); + if (this.timerid !== -1) { + clearTimeout(this.timerid); + this.timerid = -1; + } + + this.setState(newState); + + if (this.duration > 0) { + this.timerid = setTimeout(this.timeOutCB, this.duration, this); + } + + callback(null); +} + +GarageDoorOpener.prototype.timeOutCB = function (o) { + o.setState(0); + o.timerid = -1; +} + +GarageDoorOpener.prototype.gpioSensorVal = function (val) { + if (!this.invertSensorState) val = !val; + return val ? rpio.HIGH : rpio.LOW; +} + +GarageDoorOpener.prototype.gpioDoorVal = function (val) { + if (this.invertDoorState) val = !val; + return val ? rpio.HIGH : rpio.LOW; +} + +var is_int = function (n) { + return n % 1 === 0; +} + +var is_defined = function (v) { + return typeof v !== 'undefined'; +} + +var defaultVal = function (v, dflt) { + return is_defined(v) ? v : dflt; +} \ No newline at end of file diff --git a/package.json b/package.json index 51c4874..f6914fb 100644 --- a/package.json +++ b/package.json @@ -23,17 +23,13 @@ "_shasum": "73e7b822fe3761c305958587b2135cf9c3d3dd3e", "_spec": "homebridge-garage-door-wsensor", "_where": "/home/pi", - "author": { - "name": "Josh Kraft", - "email": "josh.h.kraft@gmail.com", - "url": "http://www.joshkraft.com" - }, + "author": "plhyhc", "bugs": { "url": "https://github.com/plhyhc/homebridge-garage-door-wsensor/issues" }, "bundleDependencies": false, "dependencies": { - "pi-gpio": "^0.0.8" + "rpio": "^2.1.0" }, "deprecated": false, "description": "Hombridge plugin for Garage Door Opener - Raspberry Pi", @@ -58,5 +54,5 @@ "type": "git", "url": "git+https://github.com/plhyhc/homebridge-garage-door-wsensor.git" }, - "version": "1.0.3" + "version": "2.0.0" }