11var _ = require ( 'underscore' ) ;
22var rpio = require ( 'rpio' ) ;
3- var Service , Characteristic ;
3+ var Service , Characteristic , HomebridgeAPI ;
44
55const STATE_DECREASING = 0 ;
66const STATE_INCREASING = 1 ;
@@ -9,27 +9,38 @@ const STATE_STOPPED = 2;
99module . exports = function ( homebridge ) {
1010 Service = homebridge . hap . Service ;
1111 Characteristic = homebridge . hap . Characteristic ;
12-
12+ HomebridgeAPI = homebridge ;
1313 homebridge . registerAccessory ( 'homebridge-gpio-blinds' , 'Blinds' , BlindsAccessory ) ;
1414}
1515
1616function BlindsAccessory ( log , config ) {
17- _ . defaults ( config , { activeLow : true , reedSwitchActiveLow : true } ) ;
17+ _ . defaults ( config , { durationOffset : 0 , activeLow : true , reedSwitchActiveLow : true } ) ;
1818
1919 this . log = log ;
2020 this . name = config [ 'name' ] ;
2121 this . pinUp = config [ 'pinUp' ] ;
2222 this . pinDown = config [ 'pinDown' ] ;
2323 this . durationUp = config [ 'durationUp' ] ;
2424 this . durationDown = config [ 'durationDown' ] ;
25+ this . durationOffset = config [ 'durationOffset' ] ;
2526 this . pinClosed = config [ 'pinClosed' ] ;
2627 this . pinOpen = config [ 'pinOpen' ] ;
2728 this . initialState = config [ 'activeLow' ] ? rpio . HIGH : rpio . LOW ;
2829 this . activeState = config [ 'activeLow' ] ? rpio . LOW : rpio . HIGH ;
2930 this . reedSwitchActiveState = config [ 'reedSwitchActiveLow' ] ? rpio . LOW : rpio . HIGH ;
3031
31- this . currentPosition = 0 ; // down by default
32- this . targetPosition = 0 ; // down by default
32+ this . cacheDirectory = HomebridgeAPI . user . persistPath ( ) ;
33+ this . storage = require ( 'node-persist' ) ;
34+ this . storage . initSync ( { dir :this . cacheDirectory , forgiveParseErrors : true } ) ;
35+
36+ var cachedCurrentPosition = this . storage . getItemSync ( this . name ) ;
37+ if ( ( cachedCurrentPosition === undefined ) || ( cachedCurrentPosition === false ) ) {
38+ this . currentPosition = 0 ; // down by default
39+ } else {
40+ this . currentPosition = cachedCurrentPosition ;
41+ }
42+
43+ this . targetPosition = this . currentPosition ;
3344 this . positionState = STATE_STOPPED ; // stopped by default
3445
3546 this . service = new Service . WindowCovering ( this . name ) ;
@@ -38,7 +49,7 @@ function BlindsAccessory(log, config) {
3849 this . infoService
3950 . setCharacteristic ( Characteristic . Manufacturer , 'Radoslaw Sporny' )
4051 . setCharacteristic ( Characteristic . Model , 'RaspberryPi GPIO Blinds' )
41- . setCharacteristic ( Characteristic . SerialNumber , 'Version 1.1.1 ' ) ;
52+ . setCharacteristic ( Characteristic . SerialNumber , 'Version 1.1.2 ' ) ;
4253
4354 this . finalBlindsStateTimeout ;
4455 this . togglePinTimeout ;
@@ -80,18 +91,24 @@ BlindsAccessory.prototype.getCurrentPosition = function(callback) {
8091}
8192
8293BlindsAccessory . prototype . getTargetPosition = function ( callback ) {
83- if ( this . closedAndOutOfSync ( ) ) {
94+ var updatedPosition ;
95+ if ( this . openCloseSensorMalfunction ( ) ) {
96+ this . log ( "Open and close reed switches are active, setting to 50" ) ;
97+ updatedPosition = 50 ;
98+ } else if ( this . closedAndOutOfSync ( ) ) {
8499 this . log ( "Current position is out of sync, setting to 0" ) ;
85- this . currentPosition = 0 ;
86- this . targetPosition = 0 ;
100+ updatedPosition = 0 ;
87101 } else if ( this . openAndOutOfSync ( ) ) {
88102 this . log ( "Current position is out of sync, setting to 100" ) ;
89- this . currentPosition = 100 ;
90- this . targetPosition = 100 ;
103+ updatedPosition = 100 ;
91104 } else if ( this . partiallyOpenAndOutOfSync ( ) ) {
92105 this . log ( "Current position is out of sync, setting to 50" ) ;
93- this . currentPosition = 50 ;
94- this . targetPosition = 50 ;
106+ updatedPosition = 50 ;
107+ }
108+ if ( updatedPosition !== undefined ) {
109+ this . currentPosition = updatedPosition ;
110+ this . targetPosition = updatedPosition ;
111+ this . storage . setItemSync ( this . name , updatedPosition ) ;
95112 }
96113 this . log ( "Target position: %s" , this . targetPosition ) ;
97114 callback ( null , this . targetPosition ) ;
@@ -122,10 +139,10 @@ BlindsAccessory.prototype.setTargetPosition = function(position, callback) {
122139
123140 if ( moveUp ) {
124141 duration = Math . round ( ( this . targetPosition - this . currentPosition ) / 100 * this . durationUp ) ;
125- this . currentPositionInterval = setInterval ( function ( ) { this . currentPosition ++ ; } . bind ( this ) , this . intervalUp ) ;
142+ this . currentPositionInterval = setInterval ( this . setCurrentPosition . bind ( this , moveUp ) , this . intervalUp ) ;
126143 } else {
127144 duration = Math . round ( ( this . currentPosition - this . targetPosition ) / 100 * this . durationDown ) ;
128- this . currentPositionInterval = setInterval ( function ( ) { this . currentPosition -- ; } . bind ( this ) , this . intervalDown ) ;
145+ this . currentPositionInterval = setInterval ( this . setCurrentPosition . bind ( this , moveUp ) , this . intervalDown ) ;
129146 }
130147
131148 this . log ( ( moveUp ? 'Moving up' : 'Moving down' ) + ". Duration: %s ms." , duration ) ;
@@ -142,9 +159,10 @@ BlindsAccessory.prototype.setTargetPosition = function(position, callback) {
142159
143160BlindsAccessory . prototype . togglePin = function ( pin , duration ) {
144161 if ( rpio . read ( pin ) != this . activeState ) rpio . write ( pin , this . activeState ) ;
162+ if ( this . durationOffset && ( this . targetPosition == 0 || this . targetPosition == 100 ) ) this . duration += this . durationOffset ;
145163 this . togglePinTimeout = setTimeout ( function ( ) {
146164 rpio . write ( pin , this . initialState ) ;
147- } . bind ( this ) , duration ) ;
165+ } . bind ( this ) , parseInt ( duration ) ) ;
148166}
149167
150168BlindsAccessory . prototype . setFinalBlindsState = function ( ) {
@@ -153,9 +171,19 @@ BlindsAccessory.prototype.setFinalBlindsState = function() {
153171 this . service . setCharacteristic ( Characteristic . PositionState , STATE_STOPPED ) ;
154172 this . service . setCharacteristic ( Characteristic . CurrentPosition , this . targetPosition ) ;
155173 this . currentPosition = this . targetPosition ;
174+ this . storage . setItemSync ( this . name , this . currentPosition ) ;
156175 this . log ( "Successfully moved to target position: %s" , this . targetPosition ) ;
157176}
158177
178+ BlindsAccessory . prototype . setCurrentPosition = function ( moveUp ) {
179+ if ( moveUp ) {
180+ this . currentPosition ++ ;
181+ } else {
182+ this . currentPosition -- ;
183+ }
184+ this . storage . setItemSync ( this . name , this . currentPosition ) ;
185+ }
186+
159187BlindsAccessory . prototype . closedAndOutOfSync = function ( ) {
160188 return this . currentPosition != 0 && this . pinClosed && ( rpio . read ( this . pinClosed ) == this . reedSwitchActiveState ) ;
161189}
@@ -169,6 +197,12 @@ BlindsAccessory.prototype.partiallyOpenAndOutOfSync = function() {
169197 ( this . currentPosition == 100 && this . pinOpen && ( rpio . read ( this . pinOpen ) != this . reedSwitchActiveState ) ) ;
170198}
171199
200+ BlindsAccessory . prototype . openCloseSensorMalfunction = function ( ) {
201+ return ( this . pinClosed && this . pinOpen &&
202+ ( rpio . read ( this . pinClosed ) == this . reedSwitchActiveState ) &&
203+ ( rpio . read ( this . pinOpen ) == this . reedSwitchActiveState ) ) ;
204+ }
205+
172206BlindsAccessory . prototype . oppositeDirection = function ( moveUp ) {
173207 return ( this . positionState == STATE_INCREASING && ! moveUp ) || ( this . positionState == STATE_DECREASING && moveUp ) ;
174208}
0 commit comments