homebridge-tydom 0.22.1 → 0.23.0
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/README.md +12 -0
- package/lib/accessories/basicGarageDoorOpener.d.ts +3 -0
- package/lib/accessories/basicGarageDoorOpener.js +49 -0
- package/lib/accessories/garageDoorOpener.d.ts +2 -0
- package/lib/accessories/garageDoorOpener.js +172 -23
- package/lib/utils/basic.d.ts +1 -0
- package/lib/utils/basic.js +3 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -230,6 +230,18 @@ You can also use the following environment variables (base64 encoded values)
|
|
|
230
230
|
| HOMEBRIDGE_TYDOM_PASSWORD | Tydom password |
|
|
231
231
|
| HOMEBRIDGE_TYDOM_PIN | Tyxal+ pin |
|
|
232
232
|
|
|
233
|
+
### Help
|
|
234
|
+
|
|
235
|
+
If you open a new issue, please provide a dump of your tydom configuration using node-tydom-client:
|
|
236
|
+
|
|
237
|
+
```sh
|
|
238
|
+
npx tydom-client request /configs/file /devices/data /devices/meta /devices/cmeta --file tydom_output.json --username 001A25XXXXXX --password XXXXXX
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
Will create the file `tydom_output.json` to upload, you can use [https://gist.github.com](gist.github.com).
|
|
242
|
+
|
|
243
|
+
An homebridge log with [debug enabled](https://github.com/mgcrea/homebridge-tydom#debug) while using the tydom official app (to trace working requests) can also help a lot.
|
|
244
|
+
|
|
233
245
|
### Debug
|
|
234
246
|
|
|
235
247
|
This library uses [debug](https://www.npmjs.com/package/debug) to provide high verbosity logs, just pass the following environment:
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.setupBasicGarageDoorOpener = void 0;
|
|
4
|
+
const hap_1 = require("../config/hap");
|
|
5
|
+
const accessory_1 = require("../helpers/accessory");
|
|
6
|
+
const debug_1 = require("../utils/debug");
|
|
7
|
+
const setupBasicGarageDoorOpener = (accessory, controller) => {
|
|
8
|
+
const { context } = accessory;
|
|
9
|
+
const { client } = controller;
|
|
10
|
+
const { deviceId, endpointId } = context;
|
|
11
|
+
(0, accessory_1.setupAccessoryInformationService)(accessory, controller);
|
|
12
|
+
(0, accessory_1.setupAccessoryIdentifyHandler)(accessory, controller);
|
|
13
|
+
// Add the actual accessory Service
|
|
14
|
+
const service = (0, accessory_1.addAccessoryService)(accessory, hap_1.Service.Switch, `${accessory.displayName}`, true);
|
|
15
|
+
// State
|
|
16
|
+
// const state = {
|
|
17
|
+
// isOn: false
|
|
18
|
+
// };
|
|
19
|
+
service
|
|
20
|
+
.getCharacteristic(hap_1.Characteristic.On)
|
|
21
|
+
// .on(CharacteristicEventTypes.GET, async (callback: NodeCallback<CharacteristicValue>) => {
|
|
22
|
+
// callback(null, state.isOn);
|
|
23
|
+
// })
|
|
24
|
+
.on("set" /* CharacteristicEventTypes.SET */, async (value, callback) => {
|
|
25
|
+
(0, debug_1.debugSet)(hap_1.Characteristic.On, service, value);
|
|
26
|
+
if (!value) {
|
|
27
|
+
callback();
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
try {
|
|
31
|
+
await client.put(`/devices/${deviceId}/endpoints/${endpointId}/data`, [
|
|
32
|
+
{
|
|
33
|
+
name: 'levelCmd',
|
|
34
|
+
value: 'TOGGLE'
|
|
35
|
+
}
|
|
36
|
+
]);
|
|
37
|
+
(0, debug_1.debugSetResult)(hap_1.Characteristic.On, service, value);
|
|
38
|
+
callback();
|
|
39
|
+
setTimeout(() => {
|
|
40
|
+
service.updateCharacteristic(hap_1.Characteristic.On, false);
|
|
41
|
+
}, 1000);
|
|
42
|
+
}
|
|
43
|
+
catch (err) {
|
|
44
|
+
callback(err);
|
|
45
|
+
}
|
|
46
|
+
})
|
|
47
|
+
.updateValue(false);
|
|
48
|
+
};
|
|
49
|
+
exports.setupBasicGarageDoorOpener = setupBasicGarageDoorOpener;
|
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
import type { PlatformAccessory } from 'homebridge';
|
|
2
2
|
import TydomController from '../controller';
|
|
3
|
+
import { TydomAccessoryUpdateType } from '../helpers/accessory';
|
|
3
4
|
export declare const setupGarageDoorOpener: (accessory: PlatformAccessory, controller: TydomController) => void;
|
|
5
|
+
export declare const updateGarageDoorOpener: (accessory: PlatformAccessory, _controller: TydomController, updates: Record<string, unknown>[], type: TydomAccessoryUpdateType) => void;
|
|
@@ -1,49 +1,198 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.setupGarageDoorOpener = void 0;
|
|
3
|
+
exports.updateGarageDoorOpener = exports.setupGarageDoorOpener = void 0;
|
|
4
4
|
const hap_1 = require("../config/hap");
|
|
5
5
|
const accessory_1 = require("../helpers/accessory");
|
|
6
|
+
const basic_1 = require("../utils/basic");
|
|
7
|
+
const chalk_1 = require("../utils/chalk");
|
|
6
8
|
const debug_1 = require("../utils/debug");
|
|
7
9
|
const setupGarageDoorOpener = (accessory, controller) => {
|
|
8
10
|
const { context } = accessory;
|
|
9
11
|
const { client } = controller;
|
|
10
|
-
const {
|
|
12
|
+
const { CurrentDoorState, TargetDoorState } = hap_1.Characteristic;
|
|
13
|
+
const GARAGE_DOOR_DELAY = 15 * 1000;
|
|
14
|
+
const { deviceId, endpointId, state } = context;
|
|
15
|
+
const assignState = (update) => {
|
|
16
|
+
Object.assign(state, update);
|
|
17
|
+
};
|
|
18
|
+
const assignCurrentDoorState = (currentDoorState) => {
|
|
19
|
+
Object.assign(state, { currentDoorState });
|
|
20
|
+
service.updateCharacteristic(CurrentDoorState, currentDoorState);
|
|
21
|
+
};
|
|
22
|
+
const toggleGarageDoor = async () => await client.put(`/devices/${deviceId}/endpoints/${endpointId}/data`, [
|
|
23
|
+
{
|
|
24
|
+
name: 'levelCmd',
|
|
25
|
+
value: 'TOGGLE'
|
|
26
|
+
}
|
|
27
|
+
]);
|
|
11
28
|
(0, accessory_1.setupAccessoryInformationService)(accessory, controller);
|
|
12
29
|
(0, accessory_1.setupAccessoryIdentifyHandler)(accessory, controller);
|
|
30
|
+
assignState({
|
|
31
|
+
currentDoorState: CurrentDoorState.CLOSED,
|
|
32
|
+
targetDoorState: TargetDoorState.CLOSED,
|
|
33
|
+
lastUpdatedAt: 0,
|
|
34
|
+
computedPosition: 0 // 0 <-> GARAGE_DOOR_DELAY
|
|
35
|
+
});
|
|
36
|
+
const getNextCurrentDoorState = (targetDoorState) => {
|
|
37
|
+
switch (state.currentDoorState) {
|
|
38
|
+
case CurrentDoorState.OPEN: {
|
|
39
|
+
switch (targetDoorState) {
|
|
40
|
+
case TargetDoorState.CLOSED:
|
|
41
|
+
return CurrentDoorState.OPENING;
|
|
42
|
+
case TargetDoorState.OPEN:
|
|
43
|
+
return CurrentDoorState.OPEN;
|
|
44
|
+
}
|
|
45
|
+
break;
|
|
46
|
+
}
|
|
47
|
+
case CurrentDoorState.CLOSED: {
|
|
48
|
+
switch (targetDoorState) {
|
|
49
|
+
case TargetDoorState.CLOSED:
|
|
50
|
+
return CurrentDoorState.CLOSED;
|
|
51
|
+
case TargetDoorState.OPEN:
|
|
52
|
+
return CurrentDoorState.CLOSING;
|
|
53
|
+
}
|
|
54
|
+
break;
|
|
55
|
+
}
|
|
56
|
+
case CurrentDoorState.CLOSING:
|
|
57
|
+
case CurrentDoorState.OPENING: {
|
|
58
|
+
return CurrentDoorState.STOPPED;
|
|
59
|
+
}
|
|
60
|
+
case CurrentDoorState.STOPPED: {
|
|
61
|
+
switch (targetDoorState) {
|
|
62
|
+
case TargetDoorState.CLOSED:
|
|
63
|
+
return CurrentDoorState.CLOSING;
|
|
64
|
+
case TargetDoorState.OPEN:
|
|
65
|
+
return CurrentDoorState.OPENING;
|
|
66
|
+
}
|
|
67
|
+
break;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return CurrentDoorState.CLOSED;
|
|
71
|
+
};
|
|
72
|
+
const computeCurrentPosition = () => {
|
|
73
|
+
const { lastUpdatedAt, computedPosition: lastComputedPosition, currentDoorState } = state;
|
|
74
|
+
const elapsed = lastUpdatedAt - Date.now();
|
|
75
|
+
switch (currentDoorState) {
|
|
76
|
+
case CurrentDoorState.STOPPED: {
|
|
77
|
+
return lastComputedPosition;
|
|
78
|
+
}
|
|
79
|
+
case CurrentDoorState.OPEN: {
|
|
80
|
+
return 100;
|
|
81
|
+
}
|
|
82
|
+
case CurrentDoorState.CLOSED: {
|
|
83
|
+
return 0;
|
|
84
|
+
}
|
|
85
|
+
case CurrentDoorState.OPENING: {
|
|
86
|
+
return Math.min(100, lastComputedPosition + elapsed / GARAGE_DOOR_DELAY);
|
|
87
|
+
}
|
|
88
|
+
case CurrentDoorState.CLOSING: {
|
|
89
|
+
return Math.max(0, lastComputedPosition - elapsed / GARAGE_DOOR_DELAY);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return 0;
|
|
93
|
+
};
|
|
13
94
|
// Add the actual accessory Service
|
|
14
|
-
const service = (0, accessory_1.addAccessoryService)(accessory, hap_1.Service.
|
|
15
|
-
// State
|
|
16
|
-
// const state = {
|
|
17
|
-
// isOn: false
|
|
18
|
-
// };
|
|
95
|
+
const service = (0, accessory_1.addAccessoryService)(accessory, hap_1.Service.GarageDoorOpener, `${accessory.displayName}`, true);
|
|
19
96
|
service
|
|
20
|
-
.getCharacteristic(
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
97
|
+
.getCharacteristic(CurrentDoorState)
|
|
98
|
+
.on("get" /* CharacteristicEventTypes.GET */, async (callback) => {
|
|
99
|
+
(0, debug_1.debugGet)(CurrentDoorState, service);
|
|
100
|
+
try {
|
|
101
|
+
const nextValue = state.currentDoorState;
|
|
102
|
+
(0, debug_1.debugGetResult)(CurrentDoorState, service, nextValue);
|
|
103
|
+
callback(null, nextValue);
|
|
104
|
+
}
|
|
105
|
+
catch (err) {
|
|
106
|
+
callback(err);
|
|
107
|
+
}
|
|
108
|
+
})
|
|
109
|
+
.getValue();
|
|
110
|
+
service
|
|
111
|
+
.getCharacteristic(TargetDoorState)
|
|
112
|
+
.on("get" /* CharacteristicEventTypes.GET */, async (callback) => {
|
|
113
|
+
(0, debug_1.debugGet)(TargetDoorState, service);
|
|
114
|
+
try {
|
|
115
|
+
const nextValue = state.targetDoorState;
|
|
116
|
+
(0, debug_1.debugGetResult)(TargetDoorState, service, nextValue);
|
|
117
|
+
callback(null, nextValue);
|
|
118
|
+
}
|
|
119
|
+
catch (err) {
|
|
120
|
+
callback(err);
|
|
121
|
+
}
|
|
122
|
+
})
|
|
24
123
|
.on("set" /* CharacteristicEventTypes.SET */, async (value, callback) => {
|
|
25
|
-
(0, debug_1.debugSet)(
|
|
124
|
+
(0, debug_1.debugSet)(TargetDoorState, service, value);
|
|
26
125
|
if (!value) {
|
|
27
126
|
callback();
|
|
28
127
|
return;
|
|
29
128
|
}
|
|
30
129
|
try {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
130
|
+
(0, debug_1.debugSetResult)(TargetDoorState, service, value);
|
|
131
|
+
const targetDoorState = (0, basic_1.asNumber)(value);
|
|
132
|
+
assignState({
|
|
133
|
+
targetDoorState: targetDoorState,
|
|
134
|
+
lastUpdatedAt: Date.now(),
|
|
135
|
+
computedPosition: computeCurrentPosition()
|
|
136
|
+
});
|
|
137
|
+
let nextCurrentDoorState = getNextCurrentDoorState(targetDoorState);
|
|
138
|
+
if (nextCurrentDoorState === state.currentDoorState) {
|
|
139
|
+
(0, debug_1.debug)(`nextCurrentDoorState=${(0, chalk_1.chalkNumber)(nextCurrentDoorState)} === state.currentDoorState`);
|
|
140
|
+
callback();
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
await toggleGarageDoor();
|
|
144
|
+
assignCurrentDoorState(nextCurrentDoorState);
|
|
38
145
|
callback();
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
146
|
+
// Handle Stopped state, if we are stopped, wait one second and trigger again to reverse course
|
|
147
|
+
// eg. Stopped -> Closing if target is Closed
|
|
148
|
+
if (nextCurrentDoorState === CurrentDoorState.STOPPED) {
|
|
149
|
+
await (0, basic_1.waitFor)(1000);
|
|
150
|
+
assignState({
|
|
151
|
+
targetDoorState: targetDoorState,
|
|
152
|
+
lastUpdatedAt: Date.now(),
|
|
153
|
+
computedPosition: computeCurrentPosition()
|
|
154
|
+
});
|
|
155
|
+
nextCurrentDoorState = getNextCurrentDoorState(targetDoorState);
|
|
156
|
+
await toggleGarageDoor();
|
|
157
|
+
assignCurrentDoorState(nextCurrentDoorState);
|
|
158
|
+
}
|
|
159
|
+
// Finally update pending states
|
|
160
|
+
switch (nextCurrentDoorState) {
|
|
161
|
+
case CurrentDoorState.OPENING:
|
|
162
|
+
await (0, basic_1.waitFor)((100 - state.computedPosition) * GARAGE_DOOR_DELAY);
|
|
163
|
+
assignCurrentDoorState(CurrentDoorState.OPEN);
|
|
164
|
+
break;
|
|
165
|
+
case CurrentDoorState.CLOSING:
|
|
166
|
+
await (0, basic_1.waitFor)(state.computedPosition * GARAGE_DOOR_DELAY);
|
|
167
|
+
assignCurrentDoorState(CurrentDoorState.CLOSED);
|
|
168
|
+
break;
|
|
169
|
+
}
|
|
42
170
|
}
|
|
43
171
|
catch (err) {
|
|
44
172
|
callback(err);
|
|
45
173
|
}
|
|
46
174
|
})
|
|
47
|
-
.
|
|
175
|
+
.getValue();
|
|
48
176
|
};
|
|
49
177
|
exports.setupGarageDoorOpener = setupGarageDoorOpener;
|
|
178
|
+
const updateGarageDoorOpener = (accessory, _controller, updates, type) => {
|
|
179
|
+
const { context } = accessory;
|
|
180
|
+
// const {state} = context as TydomAccessoryContext<State>;
|
|
181
|
+
// Process command updates
|
|
182
|
+
if (type === 'cdata') {
|
|
183
|
+
updates.forEach((update) => {
|
|
184
|
+
const { values } = update;
|
|
185
|
+
const { event } = values;
|
|
186
|
+
(0, debug_1.debug)(`New ${(0, chalk_1.chalkKeyword)('GarageDoorOpener')} event=${(0, chalk_1.chalkJson)(event)}`);
|
|
187
|
+
});
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
updates.forEach((update) => {
|
|
191
|
+
const { name, value } = update;
|
|
192
|
+
switch (name) {
|
|
193
|
+
default:
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
};
|
|
198
|
+
exports.updateGarageDoorOpener = updateGarageDoorOpener;
|
package/lib/utils/basic.d.ts
CHANGED
|
@@ -1,3 +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>;
|
package/lib/utils/basic.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.asNumber = exports.sameArrays = exports.stringIncludes = void 0;
|
|
3
|
+
exports.waitFor = exports.asNumber = exports.sameArrays = exports.stringIncludes = void 0;
|
|
4
4
|
const lodash_1 = require("lodash");
|
|
5
5
|
const stringIncludes = (array, value) => array.includes(value) || array.includes(`${value}`);
|
|
6
6
|
exports.stringIncludes = stringIncludes;
|
|
@@ -8,3 +8,5 @@ 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 waitFor = async (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
12
|
+
exports.waitFor = waitFor;
|