homebridge-easy-mqtt 1.1.0 → 1.2.0-beta.1

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 (64) hide show
  1. package/CHANGELOG.md +14 -1
  2. package/README.md +18 -2
  3. package/config.schema.json +167 -78
  4. package/dist/accessory/abstract/base.d.ts +32 -0
  5. package/dist/accessory/abstract/base.js +129 -0
  6. package/dist/accessory/abstract/base.js.map +1 -0
  7. package/dist/accessory/abstract/statusActive.d.ts +10 -0
  8. package/dist/accessory/abstract/statusActive.js +30 -0
  9. package/dist/accessory/abstract/statusActive.js.map +1 -0
  10. package/dist/accessory/lock.d.ts +6 -10
  11. package/dist/accessory/lock.js +41 -67
  12. package/dist/accessory/lock.js.map +1 -1
  13. package/dist/accessory/onoff/lightbulb.d.ts +21 -0
  14. package/dist/accessory/onoff/lightbulb.js +87 -0
  15. package/dist/accessory/onoff/lightbulb.js.map +1 -0
  16. package/dist/accessory/onoff/onoff.d.ts +13 -0
  17. package/dist/accessory/onoff/onoff.js +54 -0
  18. package/dist/accessory/onoff/onoff.js.map +1 -0
  19. package/dist/accessory/onoff/outlet.d.ts +13 -0
  20. package/dist/accessory/onoff/outlet.js +44 -0
  21. package/dist/accessory/onoff/outlet.js.map +1 -0
  22. package/dist/accessory/{switch.d.ts → onoff/switch.d.ts} +4 -4
  23. package/dist/accessory/{switch.js → onoff/switch.js} +2 -2
  24. package/dist/accessory/onoff/switch.js.map +1 -0
  25. package/dist/accessory/security.d.ts +22 -0
  26. package/dist/accessory/security.js +143 -0
  27. package/dist/accessory/security.js.map +1 -0
  28. package/dist/accessory/temperatureSensor.d.ts +4 -6
  29. package/dist/accessory/temperatureSensor.js +11 -15
  30. package/dist/accessory/temperatureSensor.js.map +1 -1
  31. package/dist/homebridge/platform.js +13 -8
  32. package/dist/homebridge/platform.js.map +1 -1
  33. package/dist/homebridge-ui/public/index.html +2 -2
  34. package/dist/i18n/en.d.ts +40 -2
  35. package/dist/i18n/en.js +73 -35
  36. package/dist/i18n/en.js.map +1 -1
  37. package/dist/i18n/i18n.d.ts +40 -2
  38. package/dist/i18n/template.d.ts +40 -2
  39. package/dist/model/enums.d.ts +23 -0
  40. package/dist/model/enums.js +25 -0
  41. package/dist/model/enums.js.map +1 -1
  42. package/dist/model/mqtt.d.ts +3 -3
  43. package/dist/model/mqtt.js +17 -10
  44. package/dist/model/mqtt.js.map +1 -1
  45. package/dist/model/types.d.ts +16 -2
  46. package/dist/tools/primitive.d.ts +3 -3
  47. package/dist/tools/primitive.js.map +1 -1
  48. package/package.json +1 -1
  49. package/dist/accessory/base.d.ts +0 -25
  50. package/dist/accessory/base.js +0 -59
  51. package/dist/accessory/base.js.map +0 -1
  52. package/dist/accessory/lightbulb.d.ts +0 -30
  53. package/dist/accessory/lightbulb.js +0 -106
  54. package/dist/accessory/lightbulb.js.map +0 -1
  55. package/dist/accessory/onoff.d.ts +0 -15
  56. package/dist/accessory/onoff.js +0 -57
  57. package/dist/accessory/onoff.js.map +0 -1
  58. package/dist/accessory/outlet.d.ts +0 -16
  59. package/dist/accessory/outlet.js +0 -59
  60. package/dist/accessory/outlet.js.map +0 -1
  61. package/dist/accessory/statusActive.d.ts +0 -14
  62. package/dist/accessory/statusActive.js +0 -41
  63. package/dist/accessory/statusActive.js.map +0 -1
  64. package/dist/accessory/switch.js.map +0 -1
package/CHANGELOG.md CHANGED
@@ -2,12 +2,25 @@
2
2
 
3
3
  All notable changes to homebridge-dummy will be documented in this file.
4
4
 
5
- ## 1.1.0 (2025-08-20)
5
+ ## 1.2.0-beta.1 (2025-08-??)
6
6
 
7
7
  ### HELP NEEDED! (no coding experience required)
8
8
 
9
9
  Would you like to see Homebridge Easy MQTT in your language? Please consider [getting involved](https://github.com/mpatfield/homebridge-easy-mqtt/issues/4).
10
10
 
11
+ ### Added
12
+ - Security System accessory type
13
+
14
+ ### Fixed
15
+ - Allow raw strings in mqtt messages
16
+ - Changing accessory type cleans up old Homebridge accessories
17
+
18
+ ### Changed
19
+ - Updated dev dependencies
20
+ - Significant under-the-hood refactoring to speed future development
21
+
22
+ ## 1.1.0 (2025-08-20)
23
+
11
24
  ### Added
12
25
  - Temperature Sensor accessory type
13
26
 
package/README.md CHANGED
@@ -23,7 +23,7 @@ Any issues or damage resulting from use of this plugin are not the fault of the
23
23
 
24
24
  This plugin is designed to be a simple replacement for the fantastic [homebridge-mqttthing](https://github.com/arachnetech/homebridge-mqttthing) plugin which appears as though it's [no longer](https://github.com/arachnetech/homebridge-mqttthing/commits/master/) being actively developed.
25
25
 
26
- **HomebridgeEasyMQTT** currently supports `Lightbulb`, `LockMechanism`, `Outlet`, `Switch`, and `TemperatureSensor`, but will be expanded over time as more use cases are discovered. If there is an accessory type you'd like to see supported, please feel free to [create an issue in GitHub](https://github.com/mpatfield/homebridge-easy-mqtt/issues/new/choose).
26
+ **HomebridgeEasyMQTT** currently supports `Lightbulb`, `LockMechanism`, `Outlet`, `SecuitySystem`,`Switch`, and `TemperatureSensor`, but will be expanded over time as more use cases are discovered. If there is an accessory type you'd like to see supported, please feel free to [create an issue in GitHub](https://github.com/mpatfield/homebridge-easy-mqtt/issues/new/choose).
27
27
 
28
28
  ## Configuration
29
29
 
@@ -75,7 +75,7 @@ All fields are required unless noted as "(Optional)"
75
75
  Info:
76
76
  - `id` - A unique ID to identify this accessory. Changing this value will result in a new accessory.
77
77
  - `name` - The display name for the accessory in HomeKit
78
- - `type` - The type of accessory, currently Lightbulb, LockMechanism, Outlet, Switch, and Temperature Sensor are supported
78
+ - `type` - The type of accessory, currently Lightbulb, LockMechanism, Outlet, SecuitySystem, Switch, and Temperature Sensor are supported
79
79
  - `manufacturer` - (Optional) The accessory manufacturer which will display in HomeKit device details
80
80
  - `model` - (Optional) The accessory model which will display in HomeKit device details
81
81
  - `serialNumber` - (Optional) The accessory serial number which will display in HomeKit device details
@@ -117,6 +117,13 @@ You may define topics using a JSONPath dot notation to assist the parser in find
117
117
  - `topicGetOutletInUse` - (Optional) Whether or not the outlet is currently being used
118
118
  - `topicSetOutletInUse` - (Optional) For setting whether the outlet is currently being used
119
119
 
120
+ - SecuitySystem
121
+ - `topicGetCurrentSecurityState` — The current state of the system
122
+ - `topicGetTargetSecurityState` — The target state of the system
123
+ - `topicSetTargetSecurityState` — For setting the target state of the system
124
+ - `topicGetStatusTampered` — For getting whether the system has been tampered with
125
+ - `topicGetStatusFault` — For getting whether there is a system error
126
+
120
127
  - Switch
121
128
  - `topicGetOn` - The current state of the switch, i.e. on/off
122
129
  - `topicSetOn` - For setting the state of the switch
@@ -147,6 +154,15 @@ As with Topics, you will need to populate the appropriate values based on the ty
147
154
  - `valueOutletInUse` - Currently being used, e.g. "true", or "1", or "On"
148
155
  - `valueOutletNotInUse` - Currently not being used, e.g. "false", or "0", or "Off"
149
156
 
157
+ - SecuritySystem
158
+ - `valueArmStay` — (Optional) system armed in stay mode, e.g. "SA" or "stay"
159
+ - `valueArmAway` — (Optional) system armed in away mode, e.g. "AA" or "away"
160
+ - `valueArmNight` — (Optional) system armed in night mode, e.g. "NA" or "night"
161
+ - `valueDisarm` — (Optional) system armed in away mode, e.g. "D" or "disarmed"
162
+ - `valueAlarmTriggered` — (Optional) when the alarm has been triggered, e.g. "true" or "1" or "triggered"
163
+ - `valueTampered` — (Optional) when the system has been tampered with, e.g. "true" or "1" or "tampered"
164
+ - `valueFault` — (Optional) when the system has a general fault, e.g. "true" or "1" or "fault"
165
+
150
166
  - Switch
151
167
  - `valueOn` - Turned on, e.g. "true", or "1", or "On"
152
168
  - `valueOff` - Turned off, e.g. "false", or "0", or "Off"
@@ -21,8 +21,8 @@
21
21
  "type": {
22
22
  "type": "string",
23
23
  "title": "${config.title.type}",
24
- "enum": [ "Lightbulb", "LockMechanism", "Outlet", "Switch", "TemperatureSensor"],
25
- "enumNames": ["${config.enumNames.lightbulb}", "${config.enumNames.lockMechanism}", "${config.enumNames.outlet}", "${config.enumNames.switch}", "${config.enumNames.temperatureSensor}"],
24
+ "enum": [ "Lightbulb", "LockMechanism", "Outlet", "SecuritySystem", "Switch", "TemperatureSensor"],
25
+ "enumNames": ["${config.enumNames.lightbulb}", "${config.enumNames.lockMechanism}", "${config.enumNames.outlet}", "${config.enumNames.securitySystem}", "${config.enumNames.switch}", "${config.enumNames.temperatureSensor}"],
26
26
  "required": true
27
27
  },
28
28
  "manufacturer": {
@@ -154,10 +154,29 @@
154
154
  "type": "string",
155
155
  "title": "${config.title.topicGetCurrentTemperature}"
156
156
  },
157
+ "topicGetCurrentSecurityState": {
158
+ "type": "string",
159
+ "title": "${config.title.topicGetCurrentSecurityState}"
160
+ },
161
+ "topicGetTargetSecurityState": {
162
+ "type": "string",
163
+ "title": "${config.title.topicGetTargetSecurityState}"
164
+ },
165
+ "topicSetTargetSecurityState": {
166
+ "type": "string",
167
+ "title": "${config.title.topicSetTargetSecurityState}"
168
+ },
169
+ "topicGetStatusTampered": {
170
+ "type": "string",
171
+ "title": "${config.title.topicGetStatusTampered}"
172
+ },
173
+ "topicGetStatusFault": {
174
+ "type": "string",
175
+ "title": "${config.title.topicGetStatusFault}"
176
+ },
157
177
  "valueStatusActive": {
158
178
  "type": "string",
159
- "title": "${config.title.valueStatusActive}",
160
- "description": "${config.description.valueStatusActive}"
179
+ "title": "${config.title.valueStatusActive}"
161
180
  },
162
181
  "valueLockStateSecured": {
163
182
  "type": "string",
@@ -187,6 +206,34 @@
187
206
  "type": "string",
188
207
  "title": "${config.title.valueOutletNotInUse}"
189
208
  },
209
+ "valueArmStay": {
210
+ "type": "string",
211
+ "title": "${config.title.valueArmStay}"
212
+ },
213
+ "valueArmAway": {
214
+ "type": "string",
215
+ "title": "${config.title.valueArmAway}"
216
+ },
217
+ "valueArmNight": {
218
+ "type": "string",
219
+ "title": "${config.title.valueArmNight}"
220
+ },
221
+ "valueDisarm": {
222
+ "type": "string",
223
+ "title": "${config.title.valueDisarm}"
224
+ },
225
+ "valueAlarmTriggered": {
226
+ "type": "string",
227
+ "title": "${config.title.valueAlarmTriggered}"
228
+ },
229
+ "valueTampered": {
230
+ "type": "string",
231
+ "title": "${config.title.valueTampered}"
232
+ },
233
+ "valueFault": {
234
+ "type": "string",
235
+ "title": "${config.title.valueFault}"
236
+ },
190
237
  "disableLogging": {
191
238
  "type": "boolean",
192
239
  "title": "${config.title.disableLogging}",
@@ -288,95 +335,73 @@
288
335
  {
289
336
  "type": "fieldset",
290
337
  "title": "${config.title.topics}",
338
+ "condition": {
339
+ "functionBody": "return model.accessories?.[arguments[1]]?.info?.type !== undefined;"
340
+ },
291
341
  "items": [
292
342
  {
293
- "key": "accessories[].topicGetLockCurrentState",
294
- "condition": {
295
- "functionBody": "return model.accessories?.[arguments[1]]?.info?.type === 'LockMechanism';"
296
- }
297
- },
298
- {
299
- "key": "accessories[].topicGetLockTargetState",
300
- "condition": {
301
- "functionBody": "return model.accessories?.[arguments[1]]?.info?.type === 'LockMechanism';"
302
- }
303
- },
304
- {
305
- "key": "accessories[].topicSetTargetState",
343
+ "type": "fieldset",
344
+ "notitle": "true",
345
+ "items": [
346
+ "accessories[].topicGetLockCurrentState",
347
+ "accessories[].topicGetLockTargetState",
348
+ "accessories[].topicSetTargetState"
349
+ ],
306
350
  "condition": {
307
351
  "functionBody": "return model.accessories?.[arguments[1]]?.info?.type === 'LockMechanism';"
308
352
  }
309
353
  },
310
354
  {
311
- "key": "accessories[].topicGetOn",
312
- "condition": {
313
- "functionBody": "return ['Lightbulb', 'Outlet', 'Switch'].includes(model.accessories?.[arguments[1]]?.info?.type);"
314
- }
315
- },
316
- {
317
- "key": "accessories[].topicSetOn",
355
+ "type": "fieldset",
356
+ "notitle": "true",
357
+ "items": [
358
+ "accessories[].topicGetOn",
359
+ "accessories[].topicSetOn"
360
+ ],
318
361
  "condition": {
319
362
  "functionBody": "return ['Lightbulb', 'Outlet', 'Switch'].includes(model.accessories?.[arguments[1]]?.info?.type);"
320
363
  }
321
364
  },
322
365
  {
323
- "key": "accessories[].topicGetBrightness",
324
- "condition": {
325
- "functionBody": "return model.accessories?.[arguments[1]]?.info?.type === 'Lightbulb';"
326
- }
327
- },
328
- {
329
- "key": "accessories[].topicSetBrightness",
330
- "condition": {
331
- "functionBody": "return model.accessories?.[arguments[1]]?.info?.type === 'Lightbulb';"
332
- }
333
- },
334
- {
335
- "key": "accessories[].topicGetHue",
336
- "condition": {
337
- "functionBody": "return model.accessories?.[arguments[1]]?.info?.type === 'Lightbulb';"
338
- }
339
- },
340
- {
341
- "key": "accessories[].topicSetHue",
342
- "condition": {
343
- "functionBody": "return model.accessories?.[arguments[1]]?.info?.type === 'Lightbulb';"
344
- }
345
- },
346
- {
347
- "key": "accessories[].topicGetColorTemperature",
348
- "condition": {
349
- "functionBody": "return model.accessories?.[arguments[1]]?.info?.type === 'Lightbulb';"
350
- }
351
- },
352
- {
353
- "key": "accessories[].topicSetColorTemperature",
354
- "condition": {
355
- "functionBody": "return model.accessories?.[arguments[1]]?.info?.type === 'Lightbulb';"
356
- }
357
- },
358
- {
359
- "key": "accessories[].topicGetSaturation",
360
- "condition": {
361
- "functionBody": "return model.accessories?.[arguments[1]]?.info?.type === 'Lightbulb';"
362
- }
363
- },
364
- {
365
- "key": "accessories[].topicSetSaturation",
366
+ "type": "fieldset",
367
+ "notitle": "true",
368
+ "items": [
369
+ "accessories[].topicGetBrightness",
370
+ "accessories[].topicSetBrightness",
371
+ "accessories[].topicGetHue",
372
+ "accessories[].topicSetHue",
373
+ "accessories[].topicGetColorTemperature",
374
+ "accessories[].topicSetColorTemperature",
375
+ "accessories[].topicGetSaturation",
376
+ "accessories[].topicSetSaturation"
377
+ ],
366
378
  "condition": {
367
379
  "functionBody": "return model.accessories?.[arguments[1]]?.info?.type === 'Lightbulb';"
368
380
  }
369
381
  },
370
382
  {
371
- "key": "accessories[].topicGetOutletInUse",
383
+ "type": "fieldset",
384
+ "notitle": "true",
385
+ "items": [
386
+ "accessories[].topicGetOutletInUse",
387
+ "accessories[].topicSetOutletInUse"
388
+ ],
372
389
  "condition": {
373
390
  "functionBody": "return model.accessories?.[arguments[1]]?.info?.type === 'Outlet';"
374
391
  }
375
392
  },
376
393
  {
377
- "key": "accessories[].topicSetOutletInUse",
394
+ "type": "fieldset",
395
+ "notitle": "true",
396
+ "items": [
397
+ "accessories[].topicGetCurrentSecurityState",
398
+ "accessories[].topicGetTargetSecurityState",
399
+ "accessories[].topicSetTargetSecurityState",
400
+ "accessories[].topicGetStatusTampered",
401
+ "accessories[].topicGetStatusFault"
402
+ ],
378
403
  "condition": {
379
- "functionBody": "return model.accessories?.[arguments[1]]?.info?.type === 'Outlet';"
404
+ "functionBody": "return model.accessories?.[arguments[1]]?.info?.type === 'SecuritySystem';"
380
405
  }
381
406
  },
382
407
  {
@@ -404,6 +429,9 @@
404
429
  {
405
430
  "type": "fieldset",
406
431
  "title": "${config.title.values}",
432
+ "condition": {
433
+ "functionBody": "return model.accessories?.[arguments[1]]?.info?.type !== undefined;"
434
+ },
407
435
  "items": [
408
436
  {
409
437
  "type": "div",
@@ -415,15 +443,15 @@
415
443
  "items": [
416
444
  {
417
445
  "key": "accessories[].valueLockStateSecured",
418
- "flex": "1 1 0"
446
+ "flex": "0 0 25%"
419
447
  },
420
448
  {
421
449
  "key": "accessories[].valueLockStateUnsecured",
422
- "flex": "1 1 0"
450
+ "flex": "0 0 25%"
423
451
  },
424
452
  {
425
453
  "key": "accessories[].valueLockStateJammed",
426
- "flex": "1 1 0"
454
+ "flex": "0 0 25%"
427
455
  }
428
456
  ]
429
457
  },
@@ -437,11 +465,11 @@
437
465
  "items": [
438
466
  {
439
467
  "key": "accessories[].valueOn",
440
- "flex": "1 1 0"
468
+ "flex": "0 0 25%"
441
469
  },
442
470
  {
443
471
  "key": "accessories[].valueOff",
444
- "flex": "1 1 0"
472
+ "flex": "0 0 25%"
445
473
  }
446
474
  ]
447
475
  },
@@ -455,15 +483,76 @@
455
483
  "items": [
456
484
  {
457
485
  "key": "accessories[].valueOutletInUse",
458
- "flex": "1 1 0"
486
+ "flex": "0 0 25%"
459
487
  },
460
488
  {
461
489
  "key": "accessories[].valueOutletNotInUse",
462
- "flex": "1 1 0"
490
+ "flex": "0 0 25%"
491
+ }
492
+ ]
493
+ },
494
+ {
495
+ "type": "fieldset",
496
+ "notitle": true,
497
+ "condition": {
498
+ "functionBody": "return model.accessories?.[arguments[1]]?.info?.type === 'SecuritySystem';"
499
+ },
500
+ "items": [
501
+ {
502
+ "type": "div",
503
+ "displayFlex": true,
504
+ "flex-direction": "row",
505
+ "items": [
506
+ {
507
+ "key": "accessories[].valueArmStay",
508
+ "flex": "0 0 25%"
509
+ },
510
+ {
511
+ "key": "accessories[].valueArmAway",
512
+ "flex": "0 0 25%"
513
+ },
514
+ {
515
+ "key": "accessories[].valueArmNight",
516
+ "flex": "0 0 25%"
517
+ },
518
+ {
519
+ "key": "accessories[].valueDisarm",
520
+ "flex": "0 0 25%"
521
+ }
522
+ ]
523
+ },
524
+ {
525
+ "type": "div",
526
+ "displayFlex": true,
527
+ "flex-direction": "row",
528
+ "items": [
529
+ {
530
+ "key": "accessories[].valueAlarmTriggered",
531
+ "flex": "0 0 25%"
532
+ },
533
+ {
534
+ "key": "accessories[].valueTampered",
535
+ "flex": "0 0 25%"
536
+ },
537
+ {
538
+ "key": "accessories[].valueFault",
539
+ "flex": "0 0 25%"
540
+ }
541
+ ]
463
542
  }
464
543
  ]
465
544
  },
466
- "accessories[].valueStatusActive"
545
+ {
546
+ "type": "div",
547
+ "displayFlex": true,
548
+ "flex-direction": "row",
549
+ "items": [
550
+ {
551
+ "key": "accessories[].valueStatusActive",
552
+ "flex": "0 0 25%"
553
+ }
554
+ ]
555
+ }
467
556
  ]
468
557
  }
469
558
  ]
@@ -0,0 +1,32 @@
1
+ import { CharacteristicValue, PlatformAccessory, PrimitiveTypes, Service } from 'homebridge';
2
+ import { CharacteristicKey } from '../../model/enums.js';
3
+ import { AccessoryConfig, CharacteristicType, ServiceType } from '../../model/types.js';
4
+ import { Log } from '../../tools/log.js';
5
+ export declare abstract class MQTTAccessory<C extends AccessoryConfig> {
6
+ protected readonly Service: ServiceType;
7
+ protected readonly Characteristic: CharacteristicType;
8
+ protected readonly accessory: PlatformAccessory;
9
+ protected readonly config: C;
10
+ protected readonly log: Log;
11
+ private readonly mqttClient;
12
+ private readonly properties;
13
+ private readonly topicHandlers;
14
+ protected readonly accessoryService: Service;
15
+ constructor(Service: ServiceType, Characteristic: CharacteristicType, accessory: PlatformAccessory, config: C, log: Log, caller: string);
16
+ private onMQTTConnect;
17
+ protected abstract getAccessoryService(): Service;
18
+ protected abstract addTopicHandlers(): void;
19
+ protected addTopicHandler(topicKey: keyof C, handler: (topic: string, value: PrimitiveTypes) => Promise<void>, assert?: boolean): void;
20
+ protected get name(): string;
21
+ protected getRawValue(property: keyof C, assert?: boolean): string | undefined;
22
+ protected getPrimitiveValue(property: keyof C, assert?: boolean): PrimitiveTypes | undefined;
23
+ protected publish(topic: string, value: PrimitiveTypes): void;
24
+ teardown(): void;
25
+ protected get(key: CharacteristicKey): CharacteristicValue;
26
+ protected set(key: CharacteristicKey, value: CharacteristicValue): void;
27
+ protected assert(...keys: (keyof C)[]): boolean;
28
+ protected assertNumber(value: PrimitiveTypes, error: string): boolean;
29
+ protected onUpdate(key: CharacteristicKey, value: CharacteristicValue, logString?: string | undefined): boolean;
30
+ protected onSet(key: CharacteristicKey, value: CharacteristicValue, publish: PrimitiveTypes, topic: keyof C, logString: string | undefined): void;
31
+ protected logIfDesired(message: string, ...parameters: string[]): void;
32
+ }
@@ -0,0 +1,129 @@
1
+ import { PLATFORM_NAME } from '../../homebridge/settings.js';
2
+ import { AccessoryType } from '../../model/enums.js';
3
+ import { MQTT } from '../../model/mqtt.js';
4
+ import getVersion from '../../tools/version.js';
5
+ import { assert } from '../../tools/validation.js';
6
+ import { toPrimitive } from '../../tools/primitive.js';
7
+ export class MQTTAccessory {
8
+ Service;
9
+ Characteristic;
10
+ accessory;
11
+ config;
12
+ log;
13
+ mqttClient;
14
+ properties = {};
15
+ topicHandlers = [];
16
+ accessoryService;
17
+ constructor(Service, Characteristic, accessory, config, log, caller) {
18
+ this.Service = Service;
19
+ this.Characteristic = Characteristic;
20
+ this.accessory = accessory;
21
+ this.config = config;
22
+ this.log = log;
23
+ const name = config.info.name;
24
+ if (this.assert('mqtt')) {
25
+ this.mqttClient = new MQTT(log, config.mqtt, this.onMQTTConnect.bind(this), name);
26
+ this.mqttClient.connect();
27
+ }
28
+ accessory.getService(Service.AccessoryInformation)
29
+ .setCharacteristic(Characteristic.Name, name)
30
+ .setCharacteristic(Characteristic.ConfiguredName, name)
31
+ .setCharacteristic(Characteristic.Manufacturer, config.info.manufacturer ?? 'Homebridge')
32
+ .setCharacteristic(Characteristic.SerialNumber, config.info.serialNumber ?? `${PLATFORM_NAME}:${name}`)
33
+ .setCharacteristic(Characteristic.Model, config.info.model ?? caller)
34
+ .setCharacteristic(Characteristic.FirmwareRevision, config.info.version ?? getVersion());
35
+ this.accessoryService = this.getAccessoryService();
36
+ for (const type of Object.values(AccessoryType)) {
37
+ const existingService = accessory.getService(Service[type]);
38
+ if (existingService && type !== config.info.type) {
39
+ accessory.removeService(existingService);
40
+ }
41
+ }
42
+ this.addTopicHandlers();
43
+ }
44
+ async onMQTTConnect() {
45
+ this.topicHandlers.forEach(topicHandler => {
46
+ this.mqttClient?.subscribe(topicHandler.topic, topicHandler.handler);
47
+ });
48
+ }
49
+ addTopicHandler(topicKey, handler, assert = true) {
50
+ if (!topicKey.toString().startsWith('topic')) {
51
+ throw new Error(`Trying to fetch topic with unexpected property name '${topicKey.toString()}'`);
52
+ }
53
+ if (assert && !this.assert(topicKey)) {
54
+ return;
55
+ }
56
+ const topic = this.config[topicKey];
57
+ if (topic === undefined) {
58
+ return;
59
+ }
60
+ this.topicHandlers.push({ topic: topic, handler });
61
+ }
62
+ get name() {
63
+ return this.config.info.name;
64
+ }
65
+ getRawValue(property, assert = true) {
66
+ if (!property.toString().startsWith('value')) {
67
+ throw new Error(`Trying to fetch value with unexpected property name '${property.toString()}'`);
68
+ }
69
+ if (assert && !this.assert(property)) {
70
+ return;
71
+ }
72
+ return this.config[property];
73
+ }
74
+ getPrimitiveValue(property, assert = true) {
75
+ const stringValue = this.getRawValue(property, assert);
76
+ return stringValue ? toPrimitive(stringValue) : undefined;
77
+ }
78
+ publish(topic, value) {
79
+ this.mqttClient?.publish(topic, value);
80
+ }
81
+ teardown() {
82
+ this.mqttClient?.teardown();
83
+ }
84
+ get(key) {
85
+ return this.properties[key];
86
+ }
87
+ set(key, value) {
88
+ this.properties[key] = value;
89
+ }
90
+ assert(...keys) {
91
+ return assert(this.log, this.name, this.config, ...keys);
92
+ }
93
+ assertNumber(value, error) {
94
+ if (typeof value === 'number') {
95
+ return true;
96
+ }
97
+ this.log.error(error, this.name, `'${value}'`);
98
+ return false;
99
+ }
100
+ onUpdate(key, value, logString = undefined) {
101
+ if (value === this.get(key)) {
102
+ return false;
103
+ }
104
+ this.set(key, value);
105
+ this.accessoryService.updateCharacteristic(this.Characteristic[key], value);
106
+ if (logString) {
107
+ this.logIfDesired(logString);
108
+ }
109
+ return true;
110
+ }
111
+ onSet(key, value, publish, topic, logString) {
112
+ if (!this.assert(topic)) {
113
+ return;
114
+ }
115
+ if (logString && value !== this.get(key)) {
116
+ this.logIfDesired(logString);
117
+ }
118
+ this.set(key, value);
119
+ this.accessoryService.updateCharacteristic(this.Characteristic[key], value);
120
+ this.publish(this.config[topic], publish);
121
+ }
122
+ logIfDesired(message, ...parameters) {
123
+ if (this.config.disableLogging) {
124
+ return;
125
+ }
126
+ this.log.always(message, this.name, ...parameters);
127
+ }
128
+ }
129
+ //# sourceMappingURL=base.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base.js","sourceRoot":"","sources":["../../../src/accessory/abstract/base.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import { PlatformAccessory } from 'homebridge';
2
+ import { MQTTAccessory } from './base.js';
3
+ import { CharacteristicType, StatusActiveConfig, ServiceType } from '../../model/types.js';
4
+ import { Log } from '../../tools/log.js';
5
+ export declare abstract class StatusActiveAccessory<C extends StatusActiveConfig = StatusActiveConfig> extends MQTTAccessory<C> {
6
+ constructor(Service: ServiceType, Characteristic: CharacteristicType, accessory: PlatformAccessory, config: C, log: Log, className: string);
7
+ protected addTopicHandlers(): void;
8
+ private getStatusActive;
9
+ private onStatusActiveUpdate;
10
+ }
@@ -0,0 +1,30 @@
1
+ import { MQTTAccessory } from './base.js';
2
+ import { strings } from '../../i18n/i18n.js';
3
+ import { CharacteristicKey } from '../../model/enums.js';
4
+ export class StatusActiveAccessory extends MQTTAccessory {
5
+ constructor(Service, Characteristic, accessory, config, log, className) {
6
+ super(Service, Characteristic, accessory, config, log, className);
7
+ this.set(CharacteristicKey.StatusActive, true);
8
+ this.accessoryService.getCharacteristic(Characteristic.StatusActive)
9
+ .onGet(this.getStatusActive.bind(this));
10
+ }
11
+ addTopicHandlers() {
12
+ this.addTopicHandler('topicGetStatusActive', this.onStatusActiveUpdate.bind(this), false);
13
+ }
14
+ async getStatusActive() {
15
+ return this.get(CharacteristicKey.StatusActive);
16
+ }
17
+ async onStatusActiveUpdate(topic, value) {
18
+ const statusActive = value === this.getPrimitiveValue('valueStatusActive');
19
+ if (!this.onUpdate(CharacteristicKey.StatusActive, statusActive)) {
20
+ return;
21
+ }
22
+ if (statusActive) {
23
+ this.logIfDesired(strings.accessory.statusActive);
24
+ }
25
+ else {
26
+ this.log.warning(strings.accessory.statusInactive, this.name);
27
+ }
28
+ }
29
+ }
30
+ //# sourceMappingURL=statusActive.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"statusActive.js","sourceRoot":"","sources":["../../../src/accessory/abstract/statusActive.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAE1C,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAE7C,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAKzD,MAAM,OAAgB,qBAAyE,SAAQ,aAAgB;IAErH,YAAY,OAAoB,EAAE,cAAkC,EAAE,SAA4B,EAAE,MAAS,EAAE,GAAQ,EAAE,SAAiB;QACxI,KAAK,CAAC,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,SAAS,CAAC,CAAC;QAElE,IAAI,CAAC,GAAG,CAAC,iBAAiB,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC;QAE/C,IAAI,CAAC,gBAAgB,CAAC,iBAAiB,CAAC,cAAc,CAAC,YAAY,CAAC;aACjE,KAAK,CAAC,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IAC5C,CAAC;IAES,gBAAgB;QACxB,IAAI,CAAC,eAAe,CAAC,sBAAsB,EAAE,IAAI,CAAC,oBAAoB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,KAAK,CAAC,CAAC;IAC5F,CAAC;IAEO,KAAK,CAAC,eAAe;QAC3B,OAAO,IAAI,CAAC,GAAG,CAAC,iBAAiB,CAAC,YAAY,CAAC,CAAC;IAClD,CAAC;IAEO,KAAK,CAAC,oBAAoB,CAAC,KAAa,EAAE,KAAqB;QAErE,MAAM,YAAY,GAAG,KAAK,KAAK,IAAI,CAAC,iBAAiB,CAAC,mBAAmB,CAAC,CAAC;QAC3E,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,iBAAiB,CAAC,YAAY,EAAE,YAAY,CAAC,EAAE,CAAC;YACjE,OAAO;QACT,CAAC;QAED,IAAI,YAAY,EAAE,CAAC;YACjB,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC;QACpD,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,SAAS,CAAC,cAAc,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;QAChE,CAAC;IACH,CAAC;CACF"}