homebridge-tydom 0.23.3 → 0.23.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/accessories/garageDoorOpener.js +74 -15
- package/lib/controller.js +1 -1
- package/lib/platform.js +2 -2
- package/lib/utils/basic.d.ts +1 -1
- package/lib/utils/basic.js +14 -1
- package/package.json +1 -1
|
@@ -10,12 +10,28 @@ const setupGarageDoorOpener = (accessory, controller) => {
|
|
|
10
10
|
const { context } = accessory;
|
|
11
11
|
const { client } = controller;
|
|
12
12
|
const { CurrentDoorState, TargetDoorState } = hap_1.Characteristic;
|
|
13
|
-
const GARAGE_DOOR_DELAY =
|
|
13
|
+
const GARAGE_DOOR_DELAY = 20 * 1000;
|
|
14
14
|
const { deviceId, endpointId, state } = context;
|
|
15
15
|
const assignState = (update) => {
|
|
16
16
|
Object.assign(state, update);
|
|
17
17
|
};
|
|
18
|
+
const getDoorStateLabel = (currentDoorState) => {
|
|
19
|
+
switch (currentDoorState) {
|
|
20
|
+
case CurrentDoorState.OPEN:
|
|
21
|
+
return 'OPEN';
|
|
22
|
+
case CurrentDoorState.CLOSED:
|
|
23
|
+
return 'CLOSED';
|
|
24
|
+
case CurrentDoorState.OPENING:
|
|
25
|
+
return 'OPENING';
|
|
26
|
+
case CurrentDoorState.CLOSING:
|
|
27
|
+
return 'CLOSING';
|
|
28
|
+
case CurrentDoorState.STOPPED:
|
|
29
|
+
return 'STOPPED';
|
|
30
|
+
}
|
|
31
|
+
return 'UNKNOWN';
|
|
32
|
+
};
|
|
18
33
|
const assignCurrentDoorState = (currentDoorState) => {
|
|
34
|
+
(0, debug_1.debug)(`assignCurrentDoorState=${(0, chalk_1.chalkString)(getDoorStateLabel(currentDoorState))}`);
|
|
19
35
|
Object.assign(state, { currentDoorState });
|
|
20
36
|
service.updateCharacteristic(CurrentDoorState, currentDoorState);
|
|
21
37
|
};
|
|
@@ -31,14 +47,14 @@ const setupGarageDoorOpener = (accessory, controller) => {
|
|
|
31
47
|
currentDoorState: CurrentDoorState.CLOSED,
|
|
32
48
|
targetDoorState: TargetDoorState.CLOSED,
|
|
33
49
|
lastUpdatedAt: 0,
|
|
34
|
-
computedPosition: 0 // 0 <->
|
|
50
|
+
computedPosition: 0 // 0 <-> 100%
|
|
35
51
|
});
|
|
36
52
|
const getNextCurrentDoorState = (targetDoorState) => {
|
|
37
53
|
switch (state.currentDoorState) {
|
|
38
54
|
case CurrentDoorState.OPEN: {
|
|
39
55
|
switch (targetDoorState) {
|
|
40
56
|
case TargetDoorState.CLOSED:
|
|
41
|
-
return CurrentDoorState.
|
|
57
|
+
return CurrentDoorState.CLOSING;
|
|
42
58
|
case TargetDoorState.OPEN:
|
|
43
59
|
return CurrentDoorState.OPEN;
|
|
44
60
|
}
|
|
@@ -49,7 +65,7 @@ const setupGarageDoorOpener = (accessory, controller) => {
|
|
|
49
65
|
case TargetDoorState.CLOSED:
|
|
50
66
|
return CurrentDoorState.CLOSED;
|
|
51
67
|
case TargetDoorState.OPEN:
|
|
52
|
-
return CurrentDoorState.
|
|
68
|
+
return CurrentDoorState.OPENING;
|
|
53
69
|
}
|
|
54
70
|
break;
|
|
55
71
|
}
|
|
@@ -71,7 +87,7 @@ const setupGarageDoorOpener = (accessory, controller) => {
|
|
|
71
87
|
};
|
|
72
88
|
const computeCurrentPosition = () => {
|
|
73
89
|
const { lastUpdatedAt, computedPosition: lastComputedPosition, currentDoorState } = state;
|
|
74
|
-
const elapsed =
|
|
90
|
+
const elapsed = Date.now() - lastUpdatedAt;
|
|
75
91
|
switch (currentDoorState) {
|
|
76
92
|
case CurrentDoorState.STOPPED: {
|
|
77
93
|
return lastComputedPosition;
|
|
@@ -83,10 +99,10 @@ const setupGarageDoorOpener = (accessory, controller) => {
|
|
|
83
99
|
return 0;
|
|
84
100
|
}
|
|
85
101
|
case CurrentDoorState.OPENING: {
|
|
86
|
-
return Math.min(100, lastComputedPosition + elapsed / GARAGE_DOOR_DELAY);
|
|
102
|
+
return Math.min(100, lastComputedPosition + 100 * (elapsed / GARAGE_DOOR_DELAY));
|
|
87
103
|
}
|
|
88
104
|
case CurrentDoorState.CLOSING: {
|
|
89
|
-
return Math.max(0, lastComputedPosition - elapsed / GARAGE_DOOR_DELAY);
|
|
105
|
+
return Math.max(0, lastComputedPosition - 100 * (elapsed / GARAGE_DOOR_DELAY));
|
|
90
106
|
}
|
|
91
107
|
}
|
|
92
108
|
return 0;
|
|
@@ -134,7 +150,9 @@ const setupGarageDoorOpener = (accessory, controller) => {
|
|
|
134
150
|
lastUpdatedAt: Date.now(),
|
|
135
151
|
computedPosition: computeCurrentPosition()
|
|
136
152
|
});
|
|
153
|
+
// debug(`computedPosition=${chalkNumber(state.computedPosition)}`);
|
|
137
154
|
let nextCurrentDoorState = getNextCurrentDoorState(targetDoorState);
|
|
155
|
+
// debug(`nextCurrentDoorState=${chalkString(getDoorStateLabel(nextCurrentDoorState))}`);
|
|
138
156
|
if (nextCurrentDoorState === state.currentDoorState) {
|
|
139
157
|
(0, debug_1.debug)(`nextCurrentDoorState=${(0, chalk_1.chalkNumber)(nextCurrentDoorState)} === state.currentDoorState`);
|
|
140
158
|
callback();
|
|
@@ -142,30 +160,48 @@ const setupGarageDoorOpener = (accessory, controller) => {
|
|
|
142
160
|
}
|
|
143
161
|
await toggleGarageDoor();
|
|
144
162
|
assignCurrentDoorState(nextCurrentDoorState);
|
|
145
|
-
callback();
|
|
146
163
|
// Handle Stopped state, if we are stopped, wait one second and trigger again to reverse course
|
|
147
164
|
// eg. Stopped -> Closing if target is Closed
|
|
148
165
|
if (nextCurrentDoorState === CurrentDoorState.STOPPED) {
|
|
149
|
-
await (0, basic_1.waitFor)(1000);
|
|
166
|
+
await (0, basic_1.waitFor)('stopping', 1000);
|
|
150
167
|
assignState({
|
|
151
168
|
targetDoorState: targetDoorState,
|
|
152
169
|
lastUpdatedAt: Date.now(),
|
|
153
170
|
computedPosition: computeCurrentPosition()
|
|
154
171
|
});
|
|
172
|
+
// debug(`computedPosition=${chalkNumber(state.computedPosition)}`);
|
|
155
173
|
nextCurrentDoorState = getNextCurrentDoorState(targetDoorState);
|
|
174
|
+
// debug(`nextCurrentDoorState=${chalkString(getDoorStateLabel(nextCurrentDoorState))}`);
|
|
156
175
|
await toggleGarageDoor();
|
|
157
176
|
assignCurrentDoorState(nextCurrentDoorState);
|
|
158
177
|
}
|
|
178
|
+
callback();
|
|
159
179
|
// Finally update pending states
|
|
160
180
|
switch (nextCurrentDoorState) {
|
|
161
|
-
case CurrentDoorState.OPENING:
|
|
162
|
-
|
|
163
|
-
|
|
181
|
+
case CurrentDoorState.OPENING: {
|
|
182
|
+
const delay = ((100 - state.computedPosition) * GARAGE_DOOR_DELAY) / 100;
|
|
183
|
+
// debug(`delay=${chalkNumber(delay)}`);
|
|
184
|
+
try {
|
|
185
|
+
await (0, basic_1.waitFor)(`${deviceId}.pending`, delay);
|
|
186
|
+
assignCurrentDoorState(CurrentDoorState.OPEN);
|
|
187
|
+
}
|
|
188
|
+
catch (err) {
|
|
189
|
+
// debug(`Aborted OPEN update with delay=${chalkNumber(delay)}`);
|
|
190
|
+
}
|
|
164
191
|
break;
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
192
|
+
}
|
|
193
|
+
case CurrentDoorState.CLOSING: {
|
|
194
|
+
const delay = (state.computedPosition * GARAGE_DOOR_DELAY) / 100;
|
|
195
|
+
// debug(`delay=${chalkNumber(delay)}`);
|
|
196
|
+
try {
|
|
197
|
+
await (0, basic_1.waitFor)(`${deviceId}.pending`, delay);
|
|
198
|
+
assignCurrentDoorState(CurrentDoorState.CLOSED);
|
|
199
|
+
}
|
|
200
|
+
catch (err) {
|
|
201
|
+
// debug(`Aborted CLOSED update with delay=${chalkNumber(delay)}`);
|
|
202
|
+
}
|
|
168
203
|
break;
|
|
204
|
+
}
|
|
169
205
|
}
|
|
170
206
|
}
|
|
171
207
|
catch (err) {
|
|
@@ -173,6 +209,29 @@ const setupGarageDoorOpener = (accessory, controller) => {
|
|
|
173
209
|
}
|
|
174
210
|
})
|
|
175
211
|
.getValue();
|
|
212
|
+
// const switchService = addAccessoryService(accessory, Service.Switch, `${accessory.displayName} Switch`, true);
|
|
213
|
+
// debugAddSubService(switchService, accessory);
|
|
214
|
+
// service.addLinkedService(switchService);
|
|
215
|
+
// switchService
|
|
216
|
+
// .getCharacteristic(Characteristic.On)
|
|
217
|
+
// .on(CharacteristicEventTypes.SET, async (value: CharacteristicValue, callback: CharacteristicSetCallback) => {
|
|
218
|
+
// debugSet(Characteristic.On, service, value);
|
|
219
|
+
// if (!value) {
|
|
220
|
+
// callback();
|
|
221
|
+
// return;
|
|
222
|
+
// }
|
|
223
|
+
// try {
|
|
224
|
+
// await toggleGarageDoor();
|
|
225
|
+
// debugSetResult(Characteristic.On, service, value);
|
|
226
|
+
// callback();
|
|
227
|
+
// setTimeout(() => {
|
|
228
|
+
// service.updateCharacteristic(Characteristic.On, false);
|
|
229
|
+
// }, 1000);
|
|
230
|
+
// } catch (err) {
|
|
231
|
+
// callback(err as Error);
|
|
232
|
+
// }
|
|
233
|
+
// })
|
|
234
|
+
// .updateValue(false);
|
|
176
235
|
};
|
|
177
236
|
exports.setupGarageDoorOpener = setupGarageDoorOpener;
|
|
178
237
|
const updateGarageDoorOpener = (accessory, _controller, updates, type) => {
|
package/lib/controller.js
CHANGED
|
@@ -110,7 +110,7 @@ class TydomController extends events_1.EventEmitter {
|
|
|
110
110
|
}
|
|
111
111
|
const category = categoryFromSettings || (0, tydom_1.resolveEndpointCategory)({ firstUsage, metadata });
|
|
112
112
|
if (!category) {
|
|
113
|
-
this.log.warn(`Unsupported firstUsage="${firstUsage}" for endpoint with
|
|
113
|
+
this.log.warn(`Unsupported firstUsage="${firstUsage}" for endpoint with deviceId="${deviceId}"`);
|
|
114
114
|
(0, utils_1.debug)({ endpoint });
|
|
115
115
|
return;
|
|
116
116
|
}
|
package/lib/platform.js
CHANGED
|
@@ -94,7 +94,7 @@ class TydomPlatform {
|
|
|
94
94
|
const { platformAccessory: PlatformAccessory } = this.api;
|
|
95
95
|
const { group } = context;
|
|
96
96
|
const accessoryName = category === 13 /* Categories.WINDOW */ && group ? group.name || name : name;
|
|
97
|
-
this.log.info(`Creating accessory named="${accessoryName}" with
|
|
97
|
+
this.log.info(`Creating accessory named="${accessoryName}" with deviceId="${context.deviceId}"`);
|
|
98
98
|
const accessory = new PlatformAccessory(accessoryName, id, category);
|
|
99
99
|
Object.assign(accessory.context, context);
|
|
100
100
|
await this.updateAccessory(accessory, context);
|
|
@@ -102,7 +102,7 @@ class TydomPlatform {
|
|
|
102
102
|
}
|
|
103
103
|
async updateAccessory(accessory, context) {
|
|
104
104
|
const { displayName: name, UUID: id } = accessory;
|
|
105
|
-
this.log.info(`Updating accessory named="${name}" with
|
|
105
|
+
this.log.info(`Updating accessory named="${name}" with deviceId="${context.deviceId}"`);
|
|
106
106
|
Object.assign(accessory.context, context);
|
|
107
107
|
const tydomAccessorySetup = (0, accessory_1.getTydomAccessorySetup)(accessory);
|
|
108
108
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
package/lib/utils/basic.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export declare const stringIncludes: (array: unknown[], value: string | number) => boolean;
|
|
2
2
|
export declare const sameArrays: (source: unknown[], array: unknown[]) => boolean;
|
|
3
3
|
export declare const asNumber: (maybeNumber: unknown) => number;
|
|
4
|
-
export declare const waitFor: (ms: number) => Promise<void>;
|
|
4
|
+
export declare const waitFor: (key: string, ms: number) => Promise<void>;
|
package/lib/utils/basic.js
CHANGED
|
@@ -8,5 +8,18 @@ const sameArrays = (source, array) => source.length === array.length && (0, loda
|
|
|
8
8
|
exports.sameArrays = sameArrays;
|
|
9
9
|
const asNumber = (maybeNumber) => parseInt(`${maybeNumber}`, 10);
|
|
10
10
|
exports.asNumber = asNumber;
|
|
11
|
-
const
|
|
11
|
+
const timeouts = new Map();
|
|
12
|
+
const waitFor = async (key, ms) => {
|
|
13
|
+
if (timeouts.has(key)) {
|
|
14
|
+
const { timeout, reject } = timeouts.get(key);
|
|
15
|
+
clearTimeout(timeout);
|
|
16
|
+
timeouts.delete(key);
|
|
17
|
+
reject();
|
|
18
|
+
}
|
|
19
|
+
await new Promise((resolve, reject) => {
|
|
20
|
+
const timeout = setTimeout(resolve, ms);
|
|
21
|
+
timeouts.set(key, { timeout, reject });
|
|
22
|
+
});
|
|
23
|
+
timeouts.delete(key);
|
|
24
|
+
};
|
|
12
25
|
exports.waitFor = waitFor;
|