Skip to content

Commit 1977561

Browse files
authored
Merge pull request #576 from WikingerOlaf/HmIP-WGC
Added support for the HmIP-WGC (wall mounted garage door controller)
2 parents 9fcbe92 + 7f2dc73 commit 1977561

File tree

3 files changed

+174
-0
lines changed

3 files changed

+174
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ See [Wiki](https://github.com/marcsowen/homebridge-homematicip/wiki) for details
8787
- HmIP-FSI16 full flush switch (16A)
8888
- HmIP-MOD-TM Garage door module - Tormatic
8989
- HmIP-MOD-HO Garage door module - Hörmann
90+
- HmIP-WGC Wall mounted garage door controller
9091
- HmIP-SWD Water sensor
9192
- HmIP-SLO Light sensor outdoor
9293
- HmIP-SMI Motion detector with brightness sensor - indoor

src/HmIPPlatform.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import {HmIPSmokeDetector} from './devices/HmIPSmokeDetector.js';
2121
import {HmIPButton} from './devices/HmIPButton.js';
2222
import {HmIPSwitch} from './devices/HmIPSwitch.js';
2323
import {HmIPGarageDoor} from './devices/HmIPGarageDoor.js';
24+
import {HmIPGarageDoorController} from './devices/HmIPGarageDoorController.js';
2425
import {HmIPClimateSensor} from './devices/HmIPClimateSensor.js';
2526
import {HmIPWaterSensor} from './devices/HmIPWaterSensor.js';
2627
import {HmIPBlind} from './devices/HmIPBlind.js';
@@ -325,6 +326,8 @@ export class HmIPPlatform implements DynamicPlatformPlugin {
325326
} else if (device.type === 'TORMATIC_MODULE'
326327
|| device.type === 'HOERMANN_DRIVES_MODULE') {
327328
homebridgeDevice = new HmIPGarageDoor(this, hmIPAccessory.accessory);
329+
} else if (device.type === 'WALL_MOUNTED_GARAGE_DOOR_CONTROLLER') {
330+
homebridgeDevice = new HmIPGarageDoorController(this, hmIPAccessory.accessory);
328331
} else if (device.type === 'WATER_SENSOR') {
329332
homebridgeDevice = new HmIPWaterSensor(this, hmIPAccessory.accessory);
330333
} else if (device.type === 'LIGHT_SENSOR') {
Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
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

Comments
 (0)