homebridge-tydom 0.21.9

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.
Files changed (62) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/README.md +287 -0
  3. package/config.schema.json +38 -0
  4. package/lib/accessories/contactSensor.d.ts +4 -0
  5. package/lib/accessories/contactSensor.js +49 -0
  6. package/lib/accessories/fan.d.ts +4 -0
  7. package/lib/accessories/fan.js +17 -0
  8. package/lib/accessories/garageDoorOpener.d.ts +3 -0
  9. package/lib/accessories/garageDoorOpener.js +49 -0
  10. package/lib/accessories/lightbulb.d.ts +4 -0
  11. package/lib/accessories/lightbulb.js +147 -0
  12. package/lib/accessories/securitySystem.d.ts +5 -0
  13. package/lib/accessories/securitySystem.js +422 -0
  14. package/lib/accessories/securitySystemSensors.d.ts +5 -0
  15. package/lib/accessories/securitySystemSensors.js +160 -0
  16. package/lib/accessories/services/switchableService.d.ts +5 -0
  17. package/lib/accessories/services/switchableService.js +66 -0
  18. package/lib/accessories/switch.d.ts +4 -0
  19. package/lib/accessories/switch.js +17 -0
  20. package/lib/accessories/temperatureSensor.d.ts +4 -0
  21. package/lib/accessories/temperatureSensor.js +52 -0
  22. package/lib/accessories/thermostat.d.ts +4 -0
  23. package/lib/accessories/thermostat.js +340 -0
  24. package/lib/accessories/windowCovering.d.ts +5 -0
  25. package/lib/accessories/windowCovering.js +167 -0
  26. package/lib/config/env.d.ts +3 -0
  27. package/lib/config/env.js +7 -0
  28. package/lib/config/i18n/en.d.ts +1021 -0
  29. package/lib/config/i18n/en.js +1022 -0
  30. package/lib/config/i18n/fr.d.ts +1035 -0
  31. package/lib/config/i18n/fr.js +1036 -0
  32. package/lib/config/locale.d.ts +4110 -0
  33. package/lib/config/locale.js +12 -0
  34. package/lib/controller.d.ts +40 -0
  35. package/lib/controller.js +199 -0
  36. package/lib/index.d.ts +4 -0
  37. package/lib/index.js +13 -0
  38. package/lib/platform.d.ts +37 -0
  39. package/lib/platform.js +114 -0
  40. package/lib/typings/tydom.d.ts +186 -0
  41. package/lib/typings/tydom.js +2 -0
  42. package/lib/utils/accessory.d.ts +19 -0
  43. package/lib/utils/accessory.js +139 -0
  44. package/lib/utils/array.d.ts +2 -0
  45. package/lib/utils/array.js +8 -0
  46. package/lib/utils/assert.d.ts +2 -0
  47. package/lib/utils/assert.js +9 -0
  48. package/lib/utils/chalk.d.ts +7 -0
  49. package/lib/utils/chalk.js +21 -0
  50. package/lib/utils/debug.d.ts +14 -0
  51. package/lib/utils/debug.js +44 -0
  52. package/lib/utils/hap.d.ts +6 -0
  53. package/lib/utils/hap.js +8 -0
  54. package/lib/utils/hash.d.ts +4 -0
  55. package/lib/utils/hash.js +28 -0
  56. package/lib/utils/request.d.ts +10 -0
  57. package/lib/utils/request.js +43 -0
  58. package/lib/utils/tydom.d.ts +27 -0
  59. package/lib/utils/tydom.js +126 -0
  60. package/lib/utils/webhook.d.ts +19 -0
  61. package/lib/utils/webhook.js +31 -0
  62. package/package.json +62 -0
@@ -0,0 +1,422 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
5
+ }) : (function(o, m, k, k2) {
6
+ if (k2 === undefined) k2 = k;
7
+ o[k2] = m[k];
8
+ }));
9
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
10
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
11
+ }) : function(o, v) {
12
+ o["default"] = v;
13
+ });
14
+ var __importStar = (this && this.__importStar) || function (mod) {
15
+ if (mod && mod.__esModule) return mod;
16
+ var result = {};
17
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
18
+ __setModuleDefault(result, mod);
19
+ return result;
20
+ };
21
+ var __importDefault = (this && this.__importDefault) || function (mod) {
22
+ return (mod && mod.__esModule) ? mod : { "default": mod };
23
+ };
24
+ Object.defineProperty(exports, "__esModule", { value: true });
25
+ exports.updateSecuritySystem = exports.setupSecuritySystem = void 0;
26
+ const lodash_1 = require("lodash");
27
+ const env_1 = require("../config/env");
28
+ const locale_1 = __importDefault(require("../config/locale"));
29
+ const accessory_1 = require("../utils/accessory");
30
+ const array_1 = require("../utils/array");
31
+ const assert_1 = __importDefault(require("../utils/assert"));
32
+ const chalk_1 = require("../utils/chalk");
33
+ const debug_1 = __importStar(require("../utils/debug"));
34
+ const hap_1 = require("../utils/hap");
35
+ const hash_1 = require("../utils/hash");
36
+ const tydom_1 = require("../utils/tydom");
37
+ const getActiveZones = (alarmData) => alarmData.reduce((soFar, { name, value }) => {
38
+ const matches = name.match(/zone([1-8])State/i);
39
+ if (matches && value === 'ON') {
40
+ soFar.push(accessory_1.asNumber(matches[1]));
41
+ }
42
+ return soFar;
43
+ }, []);
44
+ const getStateForActiveZones = (activeZones, zoneAliases) => {
45
+ const { SecuritySystemCurrentState } = hap_1.Characteristic;
46
+ if (zoneAliases.stay && array_1.sameArrays(activeZones, zoneAliases.stay)) {
47
+ return SecuritySystemCurrentState.STAY_ARM;
48
+ }
49
+ if (zoneAliases.night && array_1.sameArrays(activeZones, zoneAliases.night)) {
50
+ return SecuritySystemCurrentState.NIGHT_ARM;
51
+ }
52
+ return SecuritySystemCurrentState.DISARMED;
53
+ };
54
+ const getStateForAlarmData = (alarmData, zoneAliases) => {
55
+ const { SecuritySystemCurrentState } = hap_1.Characteristic;
56
+ const alarmMode = tydom_1.getTydomDataPropValue(alarmData, 'alarmMode');
57
+ const alarmState = tydom_1.getTydomDataPropValue(alarmData, 'alarmState');
58
+ if (['DELAYED', 'ON', 'QUIET'].includes(alarmState)) {
59
+ return SecuritySystemCurrentState.ALARM_TRIGGERED;
60
+ }
61
+ if (alarmMode === 'ON') {
62
+ return SecuritySystemCurrentState.AWAY_ARM;
63
+ }
64
+ if (alarmMode === 'ZONE') {
65
+ const activeZones = getActiveZones(alarmData);
66
+ return getStateForActiveZones(activeZones, zoneAliases);
67
+ }
68
+ return SecuritySystemCurrentState.DISARMED;
69
+ };
70
+ const setupSecuritySystem = async (accessory, controller) => {
71
+ const { context } = accessory;
72
+ const { client } = controller;
73
+ const { SecuritySystemTargetState, SecuritySystemCurrentState, StatusTampered, ContactSensorState, On } = hap_1.Characteristic;
74
+ const { deviceId, endpointId, settings } = context;
75
+ accessory_1.setupAccessoryInformationService(accessory, controller);
76
+ accessory_1.setupAccessoryIdentifyHandler(accessory, controller);
77
+ const aliases = (settings.aliases || {});
78
+ // Create separate dedicated sensor extra accessory;
79
+ if (settings.sensors !== false) {
80
+ const { accessoryId } = context;
81
+ const extraDevice = {
82
+ ...context,
83
+ name: `${lodash_1.get(locale_1.default, 'ALARME_ISSUES_OUVERTES', 'N/A')}`,
84
+ category: accessory_1.SECURITY_SYSTEM_SENSORS,
85
+ accessoryId: `${accessoryId}:sensors`
86
+ };
87
+ controller.emit('device', extraDevice);
88
+ }
89
+ const initialData = await tydom_1.getTydomDeviceData(client, { deviceId, endpointId });
90
+ const labelResults = await client.command(`/devices/${deviceId}/endpoints/${endpointId}/cdata?name=label`);
91
+ const { zones } = labelResults[0];
92
+ // Pin code check
93
+ const pin = env_1.HOMEBRIDGE_TYDOM_PIN ? hash_1.decode(env_1.HOMEBRIDGE_TYDOM_PIN) : settings.pin;
94
+ if (!pin) {
95
+ controller.log.warn(`Missing pin for device securitySystem, add either {"settings": {"${deviceId}": {"pin": "123456"}}} or HOMEBRIDGE_TYDOM_PIN env var (base64 encoded)`);
96
+ }
97
+ // Add the actual accessory Service
98
+ const service = accessory_1.addAccessoryService(accessory, hap_1.Service.SecuritySystem, `${accessory.displayName}`, true);
99
+ service
100
+ .getCharacteristic(SecuritySystemCurrentState)
101
+ .setValue(SecuritySystemCurrentState.DISARMED) // Default to disarmed to prevent notifications
102
+ .on("get" /* GET */, async (callback) => {
103
+ debug_1.debugGet(SecuritySystemCurrentState, service);
104
+ try {
105
+ const data = await tydom_1.getTydomDeviceData(client, { deviceId, endpointId });
106
+ const nextValue = getStateForAlarmData(data, aliases);
107
+ debug_1.debugGetResult(SecuritySystemCurrentState, service, nextValue);
108
+ callback(null, nextValue);
109
+ }
110
+ catch (err) {
111
+ callback(err);
112
+ }
113
+ })
114
+ .getValue();
115
+ service
116
+ .getCharacteristic(StatusTampered)
117
+ .on("get" /* GET */, async (callback) => {
118
+ debug_1.debugGet(StatusTampered, service);
119
+ try {
120
+ const data = await tydom_1.getTydomDeviceData(client, { deviceId, endpointId });
121
+ const systAutoProtect = tydom_1.getTydomDataPropValue(data, 'systAutoProtect');
122
+ debug_1.debugGetResult(StatusTampered, service, systAutoProtect);
123
+ callback(null, systAutoProtect);
124
+ }
125
+ catch (err) {
126
+ callback(err);
127
+ }
128
+ })
129
+ .getValue();
130
+ service
131
+ .getCharacteristic(SecuritySystemTargetState)
132
+ .on("get" /* GET */, async (callback) => {
133
+ debug_1.debugGet(SecuritySystemTargetState, service);
134
+ try {
135
+ const data = await tydom_1.getTydomDeviceData(client, { deviceId, endpointId });
136
+ const nextValue = getStateForAlarmData(data, aliases);
137
+ debug_1.debugGetResult(SecuritySystemTargetState, service, nextValue);
138
+ callback(null, nextValue);
139
+ }
140
+ catch (err) {
141
+ callback(err);
142
+ }
143
+ })
144
+ .on("set" /* SET */, async (value, callback) => {
145
+ debug_1.debugSet(SecuritySystemTargetState, service, value);
146
+ if (!pin) {
147
+ callback();
148
+ return;
149
+ }
150
+ // Clear preAlarm trigger
151
+ if ([SecuritySystemTargetState.DISARM].includes(value)) {
152
+ preAlarmService.updateCharacteristic(ContactSensorState, false);
153
+ }
154
+ // Global ON/OFF
155
+ if ([SecuritySystemTargetState.AWAY_ARM, SecuritySystemTargetState.DISARM].includes(value)) {
156
+ const tydomValue = value === SecuritySystemTargetState.DISARM ? 'OFF' : 'ON';
157
+ await client.put(`/devices/${deviceId}/endpoints/${endpointId}/cdata?name=alarmCmd`, {
158
+ value: tydomValue,
159
+ pwd: pin
160
+ });
161
+ debug_1.debugSetResult(SecuritySystemTargetState, service, value, tydomValue);
162
+ callback();
163
+ return;
164
+ }
165
+ // Zones ON/OFF
166
+ if ([SecuritySystemTargetState.STAY_ARM, SecuritySystemTargetState.NIGHT_ARM].includes(value)) {
167
+ const tydomValue = value === SecuritySystemTargetState.DISARM ? 'OFF' : 'ON';
168
+ const targetZones = value === SecuritySystemTargetState.STAY_ARM ? aliases.stay : aliases.night;
169
+ if (Array.isArray(targetZones) && targetZones.length > 0) {
170
+ await client.put(`/devices/${deviceId}/endpoints/${endpointId}/cdata?name=zoneCmd`, {
171
+ value: tydomValue,
172
+ pwd: pin,
173
+ zones: targetZones
174
+ });
175
+ }
176
+ debug_1.debugSetResult(SecuritySystemTargetState, service, value, tydomValue);
177
+ callback();
178
+ return;
179
+ }
180
+ });
181
+ // Setup systOpenIssue contactSensor
182
+ const systOpenIssueId = `systOpenIssue`;
183
+ const systOpenIssueName = lodash_1.get(locale_1.default, 'ALARME_ISSUES_OUVERTES', 'N/A');
184
+ const systOpenIssueService = accessory_1.addAccessoryServiceWithSubtype(accessory, hap_1.Service.ContactSensor, systOpenIssueName, systOpenIssueId, true);
185
+ debug_1.debugAddSubService(systOpenIssueService, accessory);
186
+ service.addLinkedService(systOpenIssueService);
187
+ systOpenIssueService
188
+ .getCharacteristic(ContactSensorState)
189
+ .on("get" /* GET */, async (callback) => {
190
+ debug_1.debugGet(ContactSensorState, systOpenIssueService);
191
+ try {
192
+ const data = (await tydom_1.getTydomDeviceData(client, { deviceId, endpointId }));
193
+ const systOpenIssue = tydom_1.getTydomDataPropValue(data, 'systOpenIssue');
194
+ debug_1.debugGetResult(ContactSensorState, systOpenIssueService, systOpenIssue);
195
+ callback(null, systOpenIssue);
196
+ }
197
+ catch (err) {
198
+ callback(err);
199
+ }
200
+ });
201
+ systOpenIssueService.getCharacteristic(hap_1.Characteristic.StatusActive).setValue(true);
202
+ systOpenIssueService.getCharacteristic(hap_1.Characteristic.StatusFault).setValue(false);
203
+ // Setup alarmSOS contactSensor
204
+ const alarmSOSId = `alarmSOS`;
205
+ const alarmSOSName = lodash_1.get(locale_1.default, 'DISCRETE_ALARM_V3', 'N/A');
206
+ const alarmSOSService = accessory_1.addAccessoryServiceWithSubtype(accessory, hap_1.Service.ContactSensor, alarmSOSName, alarmSOSId, true);
207
+ debug_1.debugAddSubService(alarmSOSService, accessory);
208
+ service.addLinkedService(alarmSOSService);
209
+ alarmSOSService
210
+ .getCharacteristic(ContactSensorState)
211
+ .on("get" /* GET */, async (callback) => {
212
+ debug_1.debugGet(ContactSensorState, alarmSOSService);
213
+ try {
214
+ const data = (await tydom_1.getTydomDeviceData(client, { deviceId, endpointId }));
215
+ const alarmSOS = tydom_1.getTydomDataPropValue(data, 'alarmSOS');
216
+ debug_1.debugGetResult(ContactSensorState, alarmSOSService, alarmSOS);
217
+ callback(null, alarmSOS);
218
+ }
219
+ catch (err) {
220
+ callback(err);
221
+ }
222
+ });
223
+ alarmSOSService.getCharacteristic(hap_1.Characteristic.StatusActive).setValue(true);
224
+ alarmSOSService.getCharacteristic(hap_1.Characteristic.StatusFault).setValue(false);
225
+ // Setup preAlarm contactSensor
226
+ const preAlarmId = `preAlarm`;
227
+ const preAlarmName = lodash_1.get(locale_1.default, 'PREALARM', 'N/A');
228
+ const preAlarmService = accessory_1.addAccessoryServiceWithSubtype(accessory, hap_1.Service.ContactSensor, preAlarmName, preAlarmId, true);
229
+ debug_1.debugAddSubService(preAlarmService, accessory);
230
+ service.addLinkedService(preAlarmService);
231
+ preAlarmService.getCharacteristic(ContactSensorState).setValue(false);
232
+ preAlarmService.getCharacteristic(hap_1.Characteristic.StatusActive).setValue(true);
233
+ preAlarmService.getCharacteristic(hap_1.Characteristic.StatusFault).setValue(false);
234
+ // Setup zones switches
235
+ for (let zoneIndex = 1; zoneIndex < 9; zoneIndex++) {
236
+ const zoneState = tydom_1.getTydomDataPropValue(initialData, `zone${zoneIndex}State`);
237
+ if (zoneState === 'UNUSED') {
238
+ continue;
239
+ }
240
+ assert_1.default(zones[zoneIndex - 1], `Unexpected missing zone label data for index ${zoneIndex}`);
241
+ const { id: productId, nameStd, nameCustom } = zones[zoneIndex - 1];
242
+ const subDeviceId = `zone_${productId}`;
243
+ const subDeviceName = nameCustom || `${nameStd ? lodash_1.get(locale_1.default, nameStd, 'N/A') : `Zone ${zoneIndex}`}`;
244
+ const zoneService = accessory_1.addAccessoryServiceWithSubtype(accessory, hap_1.Service.Switch, subDeviceName, subDeviceId, true);
245
+ debug_1.debugAddSubService(zoneService, accessory);
246
+ service.addLinkedService(zoneService);
247
+ zoneService
248
+ .getCharacteristic(On)
249
+ .on("get" /* GET */, async (callback) => {
250
+ debug_1.debugGet(On, zoneService);
251
+ try {
252
+ const data = await tydom_1.getTydomDeviceData(client, { deviceId, endpointId });
253
+ const zoneState = tydom_1.getTydomDataPropValue(data, `zone${zoneIndex}State`);
254
+ const nextValue = zoneState === 'ON';
255
+ debug_1.debugGetResult(On, zoneService, nextValue);
256
+ callback(null, nextValue);
257
+ }
258
+ catch (err) {
259
+ callback(err);
260
+ }
261
+ })
262
+ .on("set" /* SET */, async (value, callback) => {
263
+ debug_1.debugSet(On, zoneService, value);
264
+ if (!pin) {
265
+ callback();
266
+ return;
267
+ }
268
+ const tydomValue = value ? 'ON' : 'OFF';
269
+ await client.put(`/devices/${deviceId}/endpoints/${endpointId}/cdata?name=zoneCmd`, {
270
+ value: tydomValue,
271
+ pwd: pin,
272
+ zones: [zoneIndex]
273
+ });
274
+ debug_1.debugSetResult(On, zoneService, value, tydomValue);
275
+ callback();
276
+ });
277
+ }
278
+ };
279
+ exports.setupSecuritySystem = setupSecuritySystem;
280
+ const updateSecuritySystem = (accessory, controller, updates, type) => {
281
+ // Relay to separate dedicated sensor extra accessory;
282
+ const { deviceId, endpointId, accessoryId, settings } = accessory.context;
283
+ const aliases = (settings.aliases || {});
284
+ const { SecuritySystemCurrentState, ContactSensorState, On } = hap_1.Characteristic;
285
+ if (settings.sensors !== false) {
286
+ const extraUpdateContext = {
287
+ category: accessory_1.SECURITY_SYSTEM_SENSORS,
288
+ deviceId,
289
+ endpointId,
290
+ accessoryId: `${accessoryId}:sensors`
291
+ };
292
+ controller.emit('update', {
293
+ type,
294
+ updates,
295
+ context: extraUpdateContext
296
+ });
297
+ }
298
+ // Process command updates
299
+ if (type === 'cdata') {
300
+ updates.forEach((update) => {
301
+ const { name, parameters, values } = update;
302
+ // Notify with webhooks
303
+ switch (name) {
304
+ case 'eventAlarm': {
305
+ const { event } = values;
306
+ debug_1.default(`New ${chalk_1.chalkKeyword('SecuritySystem')} alarm event=${chalk_1.chalkJson(event)}`);
307
+ controller.emit('notification', {
308
+ level: 'warn',
309
+ message: `SecuritySystem \`${name}\` event, name=\`${event.name}\` parameters=\`${JSON.stringify(parameters)}\`, values=\`${JSON.stringify(values)}\``
310
+ });
311
+ switch (event.name) {
312
+ case 'arret': {
313
+ const service = accessory_1.getAccessoryService(accessory, hap_1.Service.SecuritySystem);
314
+ debug_1.debugSetUpdate(SecuritySystemCurrentState, service, SecuritySystemCurrentState.DISARMED);
315
+ service.updateCharacteristic(SecuritySystemCurrentState, SecuritySystemCurrentState.DISARMED);
316
+ return;
317
+ }
318
+ case 'marcheTotale': {
319
+ const service = accessory_1.getAccessoryService(accessory, hap_1.Service.SecuritySystem);
320
+ debug_1.debugSetUpdate(SecuritySystemCurrentState, service, SecuritySystemCurrentState.AWAY_ARM);
321
+ service.updateCharacteristic(SecuritySystemCurrentState, SecuritySystemCurrentState.AWAY_ARM);
322
+ return;
323
+ }
324
+ case 'marcheZone': {
325
+ const service = accessory_1.getAccessoryService(accessory, hap_1.Service.SecuritySystem);
326
+ const activeZones = event.zones.map((zone) => zone.id + 1);
327
+ const nextValue = getStateForActiveZones(activeZones, aliases);
328
+ debug_1.debugSetUpdate(SecuritySystemCurrentState, service, nextValue);
329
+ service.updateCharacteristic(SecuritySystemCurrentState, nextValue);
330
+ return;
331
+ }
332
+ case 'preAlarm': {
333
+ const service = accessory_1.getAccessoryServiceWithSubtype(accessory, hap_1.Service.ContactSensor, 'preAlarm');
334
+ debug_1.debugSetUpdate(ContactSensorState, service, true);
335
+ service.updateCharacteristic(ContactSensorState, true);
336
+ return;
337
+ }
338
+ default: {
339
+ return;
340
+ }
341
+ }
342
+ }
343
+ default: {
344
+ controller.emit('notification', {
345
+ level: 'debug',
346
+ message: `SecuritySystem \`${name}\` event parameters=\`${JSON.stringify(parameters)}\`, values=\`${JSON.stringify(values)}\``
347
+ });
348
+ return;
349
+ }
350
+ }
351
+ });
352
+ return;
353
+ }
354
+ updates.forEach((update) => {
355
+ const { name, value } = update;
356
+ switch (name) {
357
+ case 'alarmMode': {
358
+ const service = accessory_1.getAccessoryService(accessory, hap_1.Service.SecuritySystem);
359
+ switch (value) {
360
+ case 'OFF': {
361
+ const nextValue = SecuritySystemCurrentState.DISARMED;
362
+ debug_1.debugSetUpdate(SecuritySystemCurrentState, service, nextValue);
363
+ service.updateCharacteristic(SecuritySystemCurrentState, nextValue);
364
+ return;
365
+ }
366
+ case 'ON': {
367
+ const nextValue = SecuritySystemCurrentState.AWAY_ARM;
368
+ debug_1.debugSetUpdate(SecuritySystemCurrentState, service, nextValue);
369
+ service.updateCharacteristic(SecuritySystemCurrentState, nextValue);
370
+ return;
371
+ }
372
+ case 'ZONE': {
373
+ const activeZones = getActiveZones(updates);
374
+ const nextValue = getStateForActiveZones(activeZones, aliases);
375
+ debug_1.debugSetUpdate(SecuritySystemCurrentState, service, nextValue);
376
+ service.updateCharacteristic(SecuritySystemCurrentState, nextValue);
377
+ return;
378
+ }
379
+ default:
380
+ return;
381
+ }
382
+ }
383
+ case 'alarmSOS': {
384
+ const service = accessory_1.getAccessoryServiceWithSubtype(accessory, hap_1.Service.ContactSensor, 'alarmSOS');
385
+ const alarmSOS = !!value;
386
+ debug_1.debugSetUpdate(ContactSensorState, service, alarmSOS);
387
+ service.updateCharacteristic(ContactSensorState, alarmSOS);
388
+ return;
389
+ }
390
+ case 'zone1State':
391
+ case 'zone2State':
392
+ case 'zone3State':
393
+ case 'zone4State':
394
+ case 'zone5State':
395
+ case 'zone6State':
396
+ case 'zone7State':
397
+ case 'zone8State': {
398
+ const zoneState = value;
399
+ if (zoneState === 'UNUSED') {
400
+ return;
401
+ }
402
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
403
+ const zoneIndex = parseInt(name.match(/zone(\d+)State/)[1], 10) - 1; // @NOTE Adjust for productId starting at 0
404
+ const service = accessory_1.getAccessoryServiceWithSubtype(accessory, hap_1.Service.Switch, `zone_${zoneIndex}`);
405
+ const nextValue = zoneState === 'ON';
406
+ debug_1.debugSetUpdate(On, service, nextValue);
407
+ service.updateCharacteristic(On, nextValue);
408
+ return;
409
+ }
410
+ case 'systOpenIssue': {
411
+ const service = accessory_1.getAccessoryServiceWithSubtype(accessory, hap_1.Service.ContactSensor, 'systOpenIssue');
412
+ const systOpenIssue = !!value;
413
+ debug_1.debugSetUpdate(ContactSensorState, service, systOpenIssue);
414
+ service.updateCharacteristic(ContactSensorState, systOpenIssue);
415
+ return;
416
+ }
417
+ default:
418
+ return;
419
+ }
420
+ });
421
+ };
422
+ exports.updateSecuritySystem = updateSecuritySystem;
@@ -0,0 +1,5 @@
1
+ import type { PlatformAccessory } from 'homebridge';
2
+ import TydomController from '../controller';
3
+ import { TydomAccessoryUpdateType } from '../utils/accessory';
4
+ export declare const setupSecuritySystemSensors: (accessory: PlatformAccessory, controller: TydomController) => Promise<void>;
5
+ export declare const updateSecuritySystemSensors: (accessory: PlatformAccessory, controller: TydomController, updates: Record<string, unknown>[], type: TydomAccessoryUpdateType) => void;
@@ -0,0 +1,160 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.updateSecuritySystemSensors = exports.setupSecuritySystemSensors = void 0;
7
+ const lodash_1 = require("lodash");
8
+ const locale_1 = __importDefault(require("../config/locale"));
9
+ const accessory_1 = require("../utils/accessory");
10
+ const debug_1 = require("../utils/debug");
11
+ const hap_1 = require("../utils/hap");
12
+ const tydom_1 = require("../utils/tydom");
13
+ const getOpenedIssues = (commandResults) => lodash_1.keyBy(
14
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
15
+ commandResults.filter((result) => result.product).map((result) => result.product), 'id');
16
+ let contactSensorProducts = [];
17
+ let histoSearchParams;
18
+ const setupSecuritySystemSensors = async (accessory, controller) => {
19
+ const { context } = accessory;
20
+ const { client } = controller;
21
+ const { ContactSensorState } = hap_1.Characteristic;
22
+ const { deviceId, endpointId } = context;
23
+ accessory_1.setupAccessoryInformationService(accessory, controller);
24
+ accessory_1.setupAccessoryIdentifyHandler(accessory, controller);
25
+ const labelResults = await client.command(`/devices/${deviceId}/endpoints/${endpointId}/cdata?name=label`);
26
+ const { products } = labelResults[0];
27
+ contactSensorProducts = products.filter((product) => ['MDO'].includes(product.typeLong));
28
+ histoSearchParams = { type: 'OPEN_ISSUES', indexStart: '0', nbElem: `${contactSensorProducts.length}` };
29
+ const initialOpenedIssues = getOpenedIssues(await tydom_1.runTydomDeviceCommand(client, 'histo', {
30
+ deviceId,
31
+ endpointId,
32
+ searchParams: histoSearchParams
33
+ }));
34
+ contactSensorProducts.forEach((contactSensorProduct) => {
35
+ const { id: productId, nameStd, nameCustom, number } = contactSensorProduct;
36
+ const subDeviceId = `systOpenIssue_${productId}`;
37
+ const subDeviceName = nameCustom || `${lodash_1.get(locale_1.default, nameStd, 'N/A')}${number ? ` ${number}` : ''}`;
38
+ const contactSensorService = accessory_1.addAccessoryServiceWithSubtype(accessory, hap_1.Service.ContactSensor, subDeviceName, subDeviceId, true);
39
+ debug_1.debugAddSubService(contactSensorService, accessory);
40
+ // service.addLinkedService(contactSensorService); // @TODO ServiceLabel?
41
+ contactSensorService
42
+ .getCharacteristic(ContactSensorState)
43
+ .setValue(initialOpenedIssues[productId] ? 1 : 0)
44
+ .on("get" /* GET */, async (callback) => {
45
+ debug_1.debugGet(ContactSensorState, contactSensorService);
46
+ try {
47
+ const openedIssues = getOpenedIssues(await tydom_1.runTydomDeviceCommand(client, 'histo', {
48
+ deviceId,
49
+ endpointId,
50
+ searchParams: histoSearchParams
51
+ }));
52
+ const nextValue = openedIssues[productId] ? 1 : 0;
53
+ debug_1.debugGetResult(ContactSensorState, contactSensorService, nextValue);
54
+ callback(null, nextValue);
55
+ }
56
+ catch (err) {
57
+ callback(err);
58
+ }
59
+ });
60
+ contactSensorService.getCharacteristic(hap_1.Characteristic.StatusActive).setValue(1);
61
+ contactSensorService.getCharacteristic(hap_1.Characteristic.StatusFault).setValue(0);
62
+ });
63
+ };
64
+ exports.setupSecuritySystemSensors = setupSecuritySystemSensors;
65
+ const updateSecuritySystemSensors = (accessory, controller, updates, type) => {
66
+ const { client } = controller;
67
+ // Process command updates
68
+ if (type === 'cdata') {
69
+ return;
70
+ }
71
+ updates.forEach(async (update) => {
72
+ const { context } = accessory;
73
+ const { deviceId, endpointId } = context;
74
+ const { ContactSensorState } = hap_1.Characteristic;
75
+ const { name, value } = update;
76
+ switch (name) {
77
+ case 'systOpenIssue': {
78
+ const systOpenIssue = value;
79
+ if (!systOpenIssue) {
80
+ contactSensorProducts.forEach(({ id: productId }) => {
81
+ const subDeviceId = `systOpenIssue_${productId}`;
82
+ const service = accessory_1.getAccessoryServiceWithSubtype(accessory, hap_1.Service.ContactSensor, subDeviceId);
83
+ const nextValue = 0;
84
+ debug_1.debugSetUpdate(ContactSensorState, service, nextValue);
85
+ service.updateCharacteristic(ContactSensorState, nextValue);
86
+ });
87
+ }
88
+ else {
89
+ const openedIssues = getOpenedIssues(await tydom_1.runTydomDeviceCommand(client, 'histo', {
90
+ deviceId,
91
+ endpointId,
92
+ searchParams: histoSearchParams
93
+ }));
94
+ contactSensorProducts.forEach(({ id: productId }) => {
95
+ const subDeviceId = `systOpenIssue_${productId}`;
96
+ const service = accessory_1.getAccessoryServiceWithSubtype(accessory, hap_1.Service.ContactSensor, subDeviceId);
97
+ const nextValue = openedIssues[productId] ? 1 : 0;
98
+ debug_1.debugSetUpdate(ContactSensorState, service, nextValue);
99
+ service.updateCharacteristic(ContactSensorState, nextValue);
100
+ });
101
+ }
102
+ return;
103
+ }
104
+ default:
105
+ return;
106
+ }
107
+ });
108
+ };
109
+ exports.updateSecuritySystemSensors = updateSecuritySystemSensors;
110
+ /*
111
+ {
112
+ initialOpenedIssues: [
113
+ {
114
+ step: 0,
115
+ nbElemTot: 2,
116
+ index: 16,
117
+ product: {
118
+ typeShort: 'MDO',
119
+ typeLong: 'MDO',
120
+ id: 16,
121
+ nameStd: 'BASEMENT',
122
+ number: 3
123
+ }
124
+ },
125
+ {
126
+ step: 1,
127
+ nbElemTot: 2,
128
+ index: 17,
129
+ product: {
130
+ typeShort: 'MDO',
131
+ typeLong: 'MDO',
132
+ id: 17,
133
+ nameStd: 'BASEMENT',
134
+ number: 2
135
+ }
136
+ },
137
+ { step: 2, nbElemTot: 2, index: 51 }
138
+ ]
139
+ }
140
+ */
141
+ /*
142
+ {
143
+ openedIssues: {
144
+ '16': {
145
+ typeShort: 'MDO',
146
+ typeLong: 'MDO',
147
+ id: 16,
148
+ nameStd: 'BASEMENT',
149
+ number: 3
150
+ },
151
+ '17': {
152
+ typeShort: 'MDO',
153
+ typeLong: 'MDO',
154
+ id: 17,
155
+ nameStd: 'BASEMENT',
156
+ number: 2
157
+ }
158
+ }
159
+ }
160
+ */
@@ -0,0 +1,5 @@
1
+ import type { PlatformAccessory, Service } from 'homebridge';
2
+ import TydomController from '../../controller';
3
+ import { ServiceClass } from '../../utils/accessory';
4
+ export declare const addAccessorySwitchableService: (accessory: PlatformAccessory, controller: TydomController, serviceClass: ServiceClass) => Service;
5
+ export declare const updateAccessorySwitchableService: (accessory: PlatformAccessory, _controller: TydomController, updates: Record<string, unknown>[], ServiceClass: ServiceClass) => void;
@@ -0,0 +1,66 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.updateAccessorySwitchableService = exports.addAccessorySwitchableService = void 0;
4
+ const accessory_1 = require("../../utils/accessory");
5
+ const debug_1 = require("../../utils/debug");
6
+ const hap_1 = require("../../utils/hap");
7
+ const tydom_1 = require("../../utils/tydom");
8
+ const addAccessorySwitchableService = (accessory, controller, serviceClass) => {
9
+ const { context } = accessory;
10
+ const { client } = controller;
11
+ const { On } = hap_1.Characteristic;
12
+ const { deviceId, endpointId } = context;
13
+ const service = accessory_1.addAccessoryService(accessory, serviceClass, `${accessory.displayName}`, true);
14
+ service
15
+ .getCharacteristic(On)
16
+ .on("get" /* GET */, async (callback) => {
17
+ debug_1.debugGet(On, service);
18
+ try {
19
+ const data = (await tydom_1.getTydomDeviceData(client, { deviceId, endpointId }));
20
+ const level = tydom_1.getTydomDataPropValue(data, 'level');
21
+ const nextValue = level === 100;
22
+ debug_1.debugGetResult(On, service, nextValue);
23
+ callback(null, nextValue);
24
+ }
25
+ catch (err) {
26
+ callback(err);
27
+ }
28
+ })
29
+ .on("set" /* SET */, async (value, callback) => {
30
+ debug_1.debugSet(On, service, value);
31
+ try {
32
+ const tydomValue = value ? 100 : 0;
33
+ await client.put(`/devices/${deviceId}/endpoints/${endpointId}/data`, [
34
+ {
35
+ name: 'level',
36
+ value: tydomValue
37
+ }
38
+ ]);
39
+ debug_1.debugSetResult(On, service, value, tydomValue);
40
+ callback();
41
+ }
42
+ catch (err) {
43
+ callback(err);
44
+ }
45
+ });
46
+ return service;
47
+ };
48
+ exports.addAccessorySwitchableService = addAccessorySwitchableService;
49
+ const updateAccessorySwitchableService = (accessory, _controller, updates, ServiceClass) => {
50
+ updates.forEach((update) => {
51
+ const { name, value } = update;
52
+ const { On } = hap_1.Characteristic;
53
+ switch (name) {
54
+ case 'level': {
55
+ const service = accessory_1.getAccessoryService(accessory, ServiceClass);
56
+ const nextValue = value === 100;
57
+ debug_1.debugSetUpdate(On, service, nextValue);
58
+ service.updateCharacteristic(On, nextValue);
59
+ return;
60
+ }
61
+ default:
62
+ return;
63
+ }
64
+ });
65
+ };
66
+ exports.updateAccessorySwitchableService = updateAccessorySwitchableService;
@@ -0,0 +1,4 @@
1
+ import TydomController from '../controller';
2
+ import type { PlatformAccessory } from 'homebridge';
3
+ export declare const setupSwitch: (accessory: PlatformAccessory, controller: TydomController) => void;
4
+ export declare const updateSwitch: (accessory: PlatformAccessory, controller: TydomController, updates: Record<string, unknown>[]) => void;