1
+ import {
2
+ CharacteristicGetCallback ,
3
+ CharacteristicSetCallback ,
4
+ CharacteristicValue ,
5
+ PlatformAccessory ,
6
+ Service ,
7
+ } from 'homebridge' ;
8
+
9
+ import { HmIPPlatform } from '../HmIPPlatform.js' ;
10
+ import { HmIPDevice , HmIPGroup , Updateable } from '../HmIPState.js' ;
11
+ import { HmIPGenericDevice } from './HmIPGenericDevice.js' ;
12
+
13
+ enum DoorState {
14
+ CLOSED = 'CLOSED' ,
15
+ OPEN = 'OPEN' ,
16
+ VENTILATION_POSITION = 'VENTILATION_POSITION' ,
17
+ POSITION_UNKNOWN = 'POSITION_UNKNOWN'
18
+ }
19
+
20
+ interface ImpulseOutputChannel {
21
+ functionalChannelType : string ;
22
+ impulseDuration : number ;
23
+ processing : boolean ;
24
+ }
25
+
26
+ /**
27
+ * HomematicIP garage door controller
28
+ *
29
+ * HmIP-WGC (Wall Mounted Garage Door Controller)
30
+ *
31
+ */
32
+ export class HmIPGarageDoorController extends HmIPGenericDevice implements Updateable {
33
+ private service : Service ;
34
+
35
+ private currentDoorState : DoorState = DoorState . CLOSED ;
36
+ private previousDoorState : DoorState = DoorState . CLOSED ;
37
+ private processing = false ;
38
+ private targetDoorState : number = this . platform . Characteristic . TargetDoorState . CLOSED ;
39
+
40
+ constructor (
41
+ platform : HmIPPlatform ,
42
+ accessory : PlatformAccessory ,
43
+ ) {
44
+ super ( platform , accessory ) ;
45
+
46
+ this . platform . log . debug ( `Created garage door ${ accessory . context . device . label } ` ) ;
47
+ this . service = this . accessory . getService ( this . platform . Service . GarageDoorOpener )
48
+ || this . accessory . addService ( this . platform . Service . GarageDoorOpener ) ;
49
+ this . service . setCharacteristic ( this . platform . Characteristic . Name , accessory . context . device . label ) ;
50
+
51
+ this . service . getCharacteristic ( this . platform . Characteristic . CurrentDoorState )
52
+ . on ( 'get' , this . handleCurrentDoorStateGet . bind ( this ) ) ;
53
+
54
+ this . service . getCharacteristic ( this . platform . Characteristic . TargetDoorState )
55
+ . on ( 'get' , this . handleTargetDoorStateGet . bind ( this ) )
56
+ . on ( 'set' , this . handleTargetDoorStateSet . bind ( this ) ) ;
57
+
58
+ this . updateDevice ( accessory . context . device , platform . groups ) ;
59
+ }
60
+
61
+ handleCurrentDoorStateGet ( callback : CharacteristicGetCallback ) {
62
+ callback ( null , this . getHmKitCurrentDoorState ( this . currentDoorState ) ) ;
63
+ }
64
+
65
+ handleTargetDoorStateGet ( callback : CharacteristicGetCallback ) {
66
+ callback ( null , this . targetDoorState ) ;
67
+ }
68
+
69
+ async handleTargetDoorStateSet ( value : CharacteristicValue , callback : CharacteristicSetCallback ) {
70
+ this . targetDoorState = < number > value ;
71
+ this . platform . log . info ( 'Setting garage door %s to %s' , this . accessory . displayName ,
72
+ value === this . platform . Characteristic . TargetDoorState . OPEN ? 'OPEN' : 'CLOSED' ) ;
73
+ const body = {
74
+ channelIndex : 2 ,
75
+ deviceId : this . accessory . context . device . id ,
76
+ } ;
77
+ await this . platform . connector . apiCall ( 'device/control/startImpulse' , body ) ;
78
+ callback ( null ) ;
79
+ }
80
+
81
+ public updateDevice ( hmIPDevice : HmIPDevice , groups : { [ key : string ] : HmIPGroup } ) {
82
+ super . updateDevice ( hmIPDevice , groups ) ;
83
+ for ( const id in hmIPDevice . functionalChannels ) {
84
+ const channel = hmIPDevice . functionalChannels [ id ] ;
85
+ if ( channel . functionalChannelType === 'IMPULSE_OUTPUT_CHANNEL' ) {
86
+ const impulseOutputChannel = < ImpulseOutputChannel > channel ;
87
+ this . platform . log . debug ( `Garage door update: ${ JSON . stringify ( channel ) } ` ) ;
88
+
89
+ if ( this . targetDoorState !== this . getHmKitCurrentDoorState ( this . currentDoorState ) ) {
90
+ this . previousDoorState = this . currentDoorState ;
91
+ this . currentDoorState = this . getHmIPCurrentDoorState ( this . targetDoorState ) ;
92
+ this . platform . log . info ( 'Garage door state of %s changed to %s' , this . accessory . displayName , this . currentDoorState ) ;
93
+ this . service . updateCharacteristic ( this . platform . Characteristic . CurrentDoorState ,
94
+ this . getHmKitCurrentDoorState ( this . currentDoorState ) ) ;
95
+ }
96
+
97
+ if ( impulseOutputChannel . processing !== null && impulseOutputChannel . processing !== this . processing ) {
98
+ this . processing = impulseOutputChannel . processing ;
99
+ this . platform . log . debug ( 'Garage door processing state of %s changed to %s' , this . accessory . displayName , this . processing ) ;
100
+ if ( ! this . processing && this . currentDoorState !== DoorState . OPEN && this . currentDoorState !== DoorState . CLOSED ) {
101
+ this . service . updateCharacteristic ( this . platform . Characteristic . CurrentDoorState ,
102
+ this . platform . Characteristic . CurrentDoorState . STOPPED ) ;
103
+ }
104
+ }
105
+
106
+ this . updateTargetDoorState ( ) ;
107
+ }
108
+ }
109
+ }
110
+
111
+ private getHmKitCurrentDoorState ( hmIPDoorState : DoorState ) : number {
112
+ switch ( hmIPDoorState ) {
113
+ case DoorState . CLOSED :
114
+ return this . platform . Characteristic . CurrentDoorState . CLOSED ;
115
+ case DoorState . OPEN :
116
+ return this . platform . Characteristic . CurrentDoorState . OPEN ;
117
+ case DoorState . VENTILATION_POSITION :
118
+ return this . platform . Characteristic . CurrentDoorState . STOPPED ;
119
+ case DoorState . POSITION_UNKNOWN :
120
+ if ( this . previousDoorState === DoorState . CLOSED ) {
121
+ return this . platform . Characteristic . CurrentDoorState . OPENING ;
122
+ } else {
123
+ return this . platform . Characteristic . CurrentDoorState . CLOSING ;
124
+ }
125
+ }
126
+ }
127
+
128
+ private getHmIPCurrentDoorState ( hmKitDoorState : number ) : DoorState {
129
+ switch ( hmKitDoorState ) {
130
+ case this . platform . Characteristic . CurrentDoorState . CLOSED :
131
+ return DoorState . CLOSED ;
132
+ case this . platform . Characteristic . CurrentDoorState . OPEN :
133
+ return DoorState . OPEN ;
134
+ case this . platform . Characteristic . CurrentDoorState . STOPPED :
135
+ return DoorState . VENTILATION_POSITION ;
136
+ case this . platform . Characteristic . CurrentDoorState . OPENING :
137
+ return DoorState . POSITION_UNKNOWN ;
138
+ case this . platform . Characteristic . CurrentDoorState . CLOSING :
139
+ return DoorState . POSITION_UNKNOWN ;
140
+ }
141
+ return DoorState . POSITION_UNKNOWN
142
+ }
143
+
144
+ private updateTargetDoorState ( ) {
145
+ let newTargetDoorState : number ;
146
+
147
+ if ( this . processing ) {
148
+ if ( this . previousDoorState === DoorState . CLOSED ) {
149
+ newTargetDoorState = this . platform . Characteristic . TargetDoorState . OPEN ;
150
+ } else {
151
+ newTargetDoorState = this . platform . Characteristic . TargetDoorState . CLOSED ;
152
+ }
153
+ } else {
154
+ if ( this . currentDoorState === DoorState . CLOSED ) {
155
+ newTargetDoorState = this . platform . Characteristic . TargetDoorState . CLOSED ;
156
+ } else {
157
+ newTargetDoorState = this . platform . Characteristic . TargetDoorState . OPEN ;
158
+ }
159
+ }
160
+
161
+ if ( newTargetDoorState !== this . targetDoorState ) {
162
+ this . targetDoorState = newTargetDoorState ;
163
+ this . platform . log . info ( 'Garage door target door state of %s logically changed to %s' ,
164
+ this . accessory . displayName , this . targetDoorState ) ;
165
+ this . service . updateCharacteristic ( this . platform . Characteristic . TargetDoorState , this . targetDoorState ) ;
166
+ }
167
+ }
168
+
169
+ }
170
+
0 commit comments