homebridge-securitysystem 9.1.2 → 10.0.0-beta.2

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 (163) hide show
  1. package/.github/workflows/publish.yml +3 -0
  2. package/AGENTS.md +214 -0
  3. package/dist/conditions/already-triggered-condition.d.ts +10 -0
  4. package/dist/conditions/already-triggered-condition.js +16 -0
  5. package/dist/conditions/already-triggered-condition.js.map +1 -0
  6. package/dist/conditions/arming-in-progress-condition.d.ts +10 -0
  7. package/dist/conditions/arming-in-progress-condition.js +15 -0
  8. package/dist/conditions/arming-in-progress-condition.js.map +1 -0
  9. package/dist/conditions/arming-lock-condition.d.ts +13 -0
  10. package/dist/conditions/arming-lock-condition.js +42 -0
  11. package/dist/conditions/arming-lock-condition.js.map +1 -0
  12. package/dist/conditions/condition.d.ts +15 -0
  13. package/dist/conditions/condition.js +9 -0
  14. package/dist/conditions/condition.js.map +1 -0
  15. package/dist/conditions/double-knock-condition.d.ts +22 -0
  16. package/dist/conditions/double-knock-condition.js +70 -0
  17. package/dist/conditions/double-knock-condition.js.map +1 -0
  18. package/dist/conditions/not-armed-condition.d.ts +10 -0
  19. package/dist/conditions/not-armed-condition.js +20 -0
  20. package/dist/conditions/not-armed-condition.js.map +1 -0
  21. package/dist/constants/default-constant.d.ts +26 -0
  22. package/dist/constants/default-constant.js +28 -0
  23. package/dist/constants/default-constant.js.map +1 -0
  24. package/dist/constants/homekit-constant.d.ts +4 -0
  25. package/dist/constants/homekit-constant.js +5 -0
  26. package/dist/constants/homekit-constant.js.map +1 -0
  27. package/dist/constants/switch-uuid-constant.d.ts +23 -0
  28. package/dist/constants/switch-uuid-constant.js +24 -0
  29. package/dist/constants/switch-uuid-constant.js.map +1 -0
  30. package/dist/handlers/sensor-handler.d.ts +17 -0
  31. package/dist/handlers/sensor-handler.js +53 -0
  32. package/dist/handlers/sensor-handler.js.map +1 -0
  33. package/dist/handlers/state-handler.d.ts +41 -0
  34. package/dist/handlers/state-handler.js +213 -0
  35. package/dist/handlers/state-handler.js.map +1 -0
  36. package/dist/handlers/switch-handler.d.ts +27 -0
  37. package/dist/handlers/switch-handler.js +139 -0
  38. package/dist/handlers/switch-handler.js.map +1 -0
  39. package/dist/handlers/trip-handler.d.ts +45 -0
  40. package/dist/handlers/trip-handler.js +179 -0
  41. package/dist/handlers/trip-handler.js.map +1 -0
  42. package/dist/index.d.ts +3 -0
  43. package/dist/index.js +7 -0
  44. package/dist/index.js.map +1 -0
  45. package/dist/interfaces/condition-context-interface.d.ts +13 -0
  46. package/dist/interfaces/condition-context-interface.js +2 -0
  47. package/dist/interfaces/condition-context-interface.js.map +1 -0
  48. package/dist/interfaces/hap-types-interface.d.ts +9 -0
  49. package/dist/interfaces/hap-types-interface.js +2 -0
  50. package/dist/interfaces/hap-types-interface.js.map +1 -0
  51. package/dist/interfaces/options-interface.d.ts +93 -0
  52. package/dist/interfaces/options-interface.js +2 -0
  53. package/dist/interfaces/options-interface.js.map +1 -0
  54. package/dist/interfaces/persisted-state-interface.d.ts +6 -0
  55. package/dist/interfaces/persisted-state-interface.js +2 -0
  56. package/dist/interfaces/persisted-state-interface.js.map +1 -0
  57. package/dist/interfaces/service-registry-interface.d.ts +26 -0
  58. package/dist/interfaces/service-registry-interface.js +2 -0
  59. package/dist/interfaces/service-registry-interface.js.map +1 -0
  60. package/dist/interfaces/system-state-interface.d.ts +21 -0
  61. package/dist/interfaces/system-state-interface.js +2 -0
  62. package/dist/interfaces/system-state-interface.js.map +1 -0
  63. package/dist/security-system.d.ts +26 -0
  64. package/dist/security-system.js +377 -0
  65. package/dist/security-system.js.map +1 -0
  66. package/dist/services/audio-service.d.ts +21 -0
  67. package/dist/services/audio-service.js +113 -0
  68. package/dist/services/audio-service.js.map +1 -0
  69. package/dist/services/command-service.d.ts +16 -0
  70. package/dist/services/command-service.js +65 -0
  71. package/dist/services/command-service.js.map +1 -0
  72. package/dist/services/event-bus-service.d.ts +12 -0
  73. package/dist/services/event-bus-service.js +17 -0
  74. package/dist/services/event-bus-service.js.map +1 -0
  75. package/dist/services/server-service.d.ts +25 -0
  76. package/dist/services/server-service.js +140 -0
  77. package/dist/services/server-service.js.map +1 -0
  78. package/dist/services/storage-service.d.ts +14 -0
  79. package/dist/services/storage-service.js +70 -0
  80. package/dist/services/storage-service.js.map +1 -0
  81. package/dist/services/webhook-service.d.ts +16 -0
  82. package/dist/services/webhook-service.js +73 -0
  83. package/dist/services/webhook-service.js.map +1 -0
  84. package/dist/tests/conditions.test.d.ts +1 -0
  85. package/dist/tests/conditions.test.js +151 -0
  86. package/dist/tests/conditions.test.js.map +1 -0
  87. package/dist/tests/state-handler.test.d.ts +1 -0
  88. package/dist/tests/state-handler.test.js +171 -0
  89. package/dist/tests/state-handler.test.js.map +1 -0
  90. package/dist/tests/trip-handler.test.d.ts +1 -0
  91. package/dist/tests/trip-handler.test.js +160 -0
  92. package/dist/tests/trip-handler.test.js.map +1 -0
  93. package/dist/types/event-payload-map-type.d.ts +9 -0
  94. package/dist/types/event-payload-map-type.js +2 -0
  95. package/dist/types/event-payload-map-type.js.map +1 -0
  96. package/dist/types/event-type.d.ts +24 -0
  97. package/dist/types/event-type.js +9 -0
  98. package/dist/types/event-type.js.map +1 -0
  99. package/dist/types/mode-type.d.ts +4 -0
  100. package/dist/types/mode-type.js +2 -0
  101. package/dist/types/mode-type.js.map +1 -0
  102. package/dist/types/origin-type.d.ts +9 -0
  103. package/dist/types/origin-type.js +11 -0
  104. package/dist/types/origin-type.js.map +1 -0
  105. package/dist/types/security-state-type.d.ts +11 -0
  106. package/dist/types/security-state-type.js +13 -0
  107. package/dist/types/security-state-type.js.map +1 -0
  108. package/dist/utils/log-util.d.ts +4 -0
  109. package/dist/utils/log-util.js +47 -0
  110. package/dist/utils/log-util.js.map +1 -0
  111. package/dist/utils/options-util.d.ts +6 -0
  112. package/dist/utils/options-util.js +171 -0
  113. package/dist/utils/options-util.js.map +1 -0
  114. package/dist/utils/state-util.d.ts +8 -0
  115. package/dist/utils/state-util.js +29 -0
  116. package/dist/utils/state-util.js.map +1 -0
  117. package/eslint.config.js +35 -0
  118. package/package.json +40 -34
  119. package/src/@types/homebridge-lib.d.ts +14 -0
  120. package/src/conditions/already-triggered-condition.ts +18 -0
  121. package/src/conditions/arming-in-progress-condition.ts +17 -0
  122. package/src/conditions/arming-lock-condition.ts +48 -0
  123. package/src/conditions/condition.ts +17 -0
  124. package/src/conditions/double-knock-condition.ts +82 -0
  125. package/src/conditions/not-armed-condition.ts +24 -0
  126. package/src/constants/default-constant.ts +28 -0
  127. package/src/constants/homekit-constant.ts +5 -0
  128. package/src/constants/switch-uuid-constant.ts +23 -0
  129. package/src/handlers/sensor-handler.ts +81 -0
  130. package/src/handlers/state-handler.ts +268 -0
  131. package/src/handlers/switch-handler.ts +166 -0
  132. package/src/handlers/trip-handler.ts +219 -0
  133. package/src/index.ts +9 -0
  134. package/src/interfaces/condition-context-interface.ts +14 -0
  135. package/src/interfaces/hap-types-interface.ts +11 -0
  136. package/src/interfaces/options-interface.ts +120 -0
  137. package/src/interfaces/persisted-state-interface.ts +7 -0
  138. package/src/interfaces/service-registry-interface.ts +37 -0
  139. package/src/interfaces/system-state-interface.ts +25 -0
  140. package/src/security-system.ts +433 -0
  141. package/src/services/audio-service.ts +133 -0
  142. package/src/services/command-service.ts +76 -0
  143. package/src/services/event-bus-service.ts +21 -0
  144. package/src/services/server-service.ts +176 -0
  145. package/src/services/storage-service.ts +80 -0
  146. package/src/services/webhook-service.ts +83 -0
  147. package/src/tests/conditions.test.ts +180 -0
  148. package/src/tests/state-handler.test.ts +200 -0
  149. package/src/tests/trip-handler.test.ts +182 -0
  150. package/src/types/event-payload-map-type.ts +15 -0
  151. package/src/types/event-type.ts +29 -0
  152. package/src/types/mode-type.ts +4 -0
  153. package/src/types/origin-type.ts +9 -0
  154. package/src/types/security-state-type.ts +11 -0
  155. package/src/utils/log-util.ts +54 -0
  156. package/src/utils/options-util.ts +202 -0
  157. package/src/utils/state-util.ts +32 -0
  158. package/tsconfig.json +25 -0
  159. package/vitest.config.ts +8 -0
  160. package/.eslintrc.js +0 -16
  161. package/.vscode/settings.json +0 -12
  162. package/src/index.js +0 -2525
  163. package/src/utils/options.js +0 -409
@@ -0,0 +1,171 @@
1
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
2
+ import { SecurityState } from '../types/security-state-type.js';
3
+ import { OriginType } from '../types/origin-type.js';
4
+ // ── Minimal mocks ─────────────────────────────────────────────────────────────
5
+ function makeMockChar(initialValue = false) {
6
+ const char = { value: initialValue, updateValue: vi.fn(), setProps: vi.fn() };
7
+ char.updateValue.mockImplementation((v) => {
8
+ char.value = v;
9
+ });
10
+ return char;
11
+ }
12
+ function makeMockService(charValue = false) {
13
+ const char = makeMockChar(charValue);
14
+ return {
15
+ getCharacteristic: vi.fn().mockReturnValue(char),
16
+ setCharacteristic: vi.fn().mockReturnThis(),
17
+ updateCharacteristic: vi.fn(),
18
+ addCharacteristic: vi.fn(),
19
+ addOptionalCharacteristic: vi.fn(),
20
+ };
21
+ }
22
+ function makeServices() {
23
+ const s = {};
24
+ const keys = [
25
+ 'mainService', 'accessoryInfoService', 'tripSwitchService', 'tripHomeSwitchService',
26
+ 'tripAwaySwitchService', 'tripNightSwitchService', 'tripOverrideSwitchService',
27
+ 'armingLockSwitchService', 'armingLockHomeSwitchService', 'armingLockAwaySwitchService',
28
+ 'armingLockNightSwitchService', 'modeHomeSwitchService', 'modeAwaySwitchService',
29
+ 'modeNightSwitchService', 'modeOffSwitchService', 'modeAwayExtendedSwitchService',
30
+ 'modePauseSwitchService', 'audioSwitchService', 'armingMotionSensorService',
31
+ 'trippedMotionSensorService', 'triggeredMotionSensorService', 'triggeredResetMotionSensorService',
32
+ ];
33
+ for (const k of keys) {
34
+ s[k] = makeMockService();
35
+ }
36
+ return s;
37
+ }
38
+ function makeState(overrides = {}) {
39
+ return {
40
+ currentState: SecurityState.OFF,
41
+ targetState: SecurityState.OFF,
42
+ defaultState: SecurityState.OFF,
43
+ availableTargetStates: [SecurityState.HOME, SecurityState.AWAY, SecurityState.NIGHT, SecurityState.OFF],
44
+ isArming: false,
45
+ isKnocked: false,
46
+ invalidCodeCount: 0,
47
+ pausedCurrentState: null,
48
+ audioProcess: null,
49
+ armTimeout: null,
50
+ pauseTimeout: null,
51
+ triggerTimeout: null,
52
+ doubleKnockTimeout: null,
53
+ resetTimeout: null,
54
+ trippedMotionSensorInterval: null,
55
+ triggeredMotionSensorInterval: null,
56
+ ...overrides,
57
+ };
58
+ }
59
+ function makeOptions(overrides = {}) {
60
+ return {
61
+ armSeconds: 0,
62
+ triggerSeconds: 0,
63
+ resetMinutes: 10,
64
+ testMode: false,
65
+ proxyMode: false,
66
+ saveState: false,
67
+ armingLockSwitch: false,
68
+ armingLockSwitches: false,
69
+ disabledModes: [],
70
+ homeArmSeconds: null,
71
+ awayArmSeconds: null,
72
+ nightArmSeconds: null,
73
+ homeTriggerSeconds: null,
74
+ awayTriggerSeconds: null,
75
+ nightTriggerSeconds: null,
76
+ triggeredMotionSensor: false,
77
+ triggeredMotionSensorSeconds: 5,
78
+ trippedMotionSensor: false,
79
+ trippedMotionSensorSeconds: 5,
80
+ resetOffFlow: false,
81
+ ...overrides,
82
+ };
83
+ }
84
+ function makeMockLog() {
85
+ return { info: vi.fn(), warn: vi.fn(), error: vi.fn(), debug: vi.fn() };
86
+ }
87
+ function makeStorage() {
88
+ return { save: vi.fn(), load: vi.fn(), init: vi.fn() };
89
+ }
90
+ function makeAudio() {
91
+ return { play: vi.fn(), stop: vi.fn(), attachToBus: vi.fn() };
92
+ }
93
+ function makeMockSensor() {
94
+ return {
95
+ resetArmingMotionSensor: vi.fn(),
96
+ resetTrippedMotionSensor: vi.fn(),
97
+ pulseResetMotionSensor: vi.fn(),
98
+ updateArmingMotionSensor: vi.fn(),
99
+ };
100
+ }
101
+ // ── StateHandler tests ────────────────────────────────────────────────────────
102
+ describe('StateHandler.getArmingSeconds', async () => {
103
+ const { StateHandler } = await import('../handlers/state-handler.js');
104
+ let stateHandler;
105
+ let state;
106
+ beforeEach(async () => {
107
+ const { EventBusService } = await import('../services/event-bus-service.js');
108
+ state = makeState();
109
+ const services = makeServices();
110
+ const options = makeOptions();
111
+ const log = makeMockLog();
112
+ const bus = new EventBusService();
113
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
114
+ stateHandler = new StateHandler(services, state, options, {}, log, bus, makeStorage(), makeAudio());
115
+ });
116
+ it('returns 0 when current state is TRIGGERED', () => {
117
+ state.currentState = SecurityState.TRIGGERED;
118
+ expect(stateHandler.getArmingSeconds(SecurityState.HOME)).toBe(0);
119
+ });
120
+ it('returns 0 when target state is OFF (disarm)', () => {
121
+ state.currentState = SecurityState.HOME;
122
+ expect(stateHandler.getArmingSeconds(SecurityState.OFF)).toBe(0);
123
+ });
124
+ it('returns global armSeconds when no mode-specific value', () => {
125
+ state.currentState = SecurityState.HOME;
126
+ expect(stateHandler.getArmingSeconds(SecurityState.AWAY)).toBe(0);
127
+ });
128
+ });
129
+ // ── StateHandler.updateTargetState ───────────────────────────────────────────
130
+ describe('StateHandler.updateTargetState', async () => {
131
+ const { StateHandler } = await import('../handlers/state-handler.js');
132
+ const { EventBusService } = await import('../services/event-bus-service.js');
133
+ it('returns false when target state is already set (not triggered)', async () => {
134
+ const state = makeState({ currentState: SecurityState.HOME, targetState: SecurityState.HOME });
135
+ const log = makeMockLog();
136
+ const bus = new EventBusService();
137
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
138
+ const handler = new StateHandler(makeServices(), state, makeOptions(), {}, log, bus, makeStorage(), makeAudio());
139
+ const mockTrip = { resetTripSwitches: vi.fn() };
140
+ const mockSw = {
141
+ resetModeSwitches: vi.fn(),
142
+ updateModeSwitches: vi.fn(),
143
+ isArmingLocked: vi.fn().mockReturnValue(false),
144
+ };
145
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
146
+ handler.setHandlers(mockTrip, mockSw, makeMockSensor());
147
+ const result = handler.updateTargetState(SecurityState.HOME, OriginType.INTERNAL, 0);
148
+ expect(result).toBe(false);
149
+ expect(log.warn).toHaveBeenCalledWith('Target mode (Already set)');
150
+ });
151
+ it('transitions to a new armed mode', async () => {
152
+ const state = makeState({ currentState: SecurityState.OFF, targetState: SecurityState.OFF });
153
+ const log = makeMockLog();
154
+ const bus = new EventBusService();
155
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
156
+ const handler = new StateHandler(makeServices(), state, makeOptions(), {}, log, bus, makeStorage(), makeAudio());
157
+ const mockTrip = { resetTripSwitches: vi.fn() };
158
+ const mockSw = {
159
+ resetModeSwitches: vi.fn(),
160
+ updateModeSwitches: vi.fn(),
161
+ isArmingLocked: vi.fn().mockReturnValue(false),
162
+ };
163
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
164
+ handler.setHandlers(mockTrip, mockSw, makeMockSensor());
165
+ const result = handler.updateTargetState(SecurityState.HOME, OriginType.REGULAR_SWITCH, 0);
166
+ // armSeconds=0 → synchronous transition; function returns false after setCurrentState
167
+ expect(result).toBe(false);
168
+ expect(state.targetState).toBe(SecurityState.HOME);
169
+ });
170
+ });
171
+ //# sourceMappingURL=state-handler.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state-handler.test.js","sourceRoot":"","sources":["../../src/tests/state-handler.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,160 @@
1
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
2
+ import { SecurityState } from '../types/security-state-type.js';
3
+ import { OriginType } from '../types/origin-type.js';
4
+ // ── Helpers (shared with state-handler.test) ──────────────────────────────────
5
+ function makeMockChar(value = false) {
6
+ const c = { value, updateValue: vi.fn() };
7
+ c.updateValue.mockImplementation((v) => {
8
+ c.value = v;
9
+ });
10
+ return c;
11
+ }
12
+ function makeMockService(charValue = false) {
13
+ const char = makeMockChar(charValue);
14
+ return {
15
+ getCharacteristic: vi.fn().mockReturnValue(char),
16
+ updateCharacteristic: vi.fn(),
17
+ setCharacteristic: vi.fn().mockReturnThis(),
18
+ addCharacteristic: vi.fn(),
19
+ addOptionalCharacteristic: vi.fn(),
20
+ };
21
+ }
22
+ function makeServices() {
23
+ const keys = [
24
+ 'mainService', 'tripSwitchService', 'tripHomeSwitchService', 'tripAwaySwitchService',
25
+ 'tripNightSwitchService', 'tripOverrideSwitchService', 'armingLockSwitchService',
26
+ 'armingLockHomeSwitchService', 'armingLockAwaySwitchService', 'armingLockNightSwitchService',
27
+ 'modeHomeSwitchService', 'modeAwaySwitchService', 'modeNightSwitchService',
28
+ 'modeOffSwitchService', 'modeAwayExtendedSwitchService', 'modePauseSwitchService',
29
+ 'audioSwitchService', 'armingMotionSensorService', 'trippedMotionSensorService',
30
+ 'triggeredMotionSensorService', 'triggeredResetMotionSensorService', 'accessoryInfoService',
31
+ ];
32
+ const s = {};
33
+ for (const k of keys) {
34
+ s[k] = makeMockService();
35
+ }
36
+ return s;
37
+ }
38
+ function makeState(overrides = {}) {
39
+ return {
40
+ currentState: SecurityState.HOME,
41
+ targetState: SecurityState.HOME,
42
+ defaultState: SecurityState.OFF,
43
+ availableTargetStates: [SecurityState.HOME, SecurityState.AWAY, SecurityState.NIGHT, SecurityState.OFF],
44
+ isArming: false,
45
+ isKnocked: false,
46
+ invalidCodeCount: 0,
47
+ pausedCurrentState: null,
48
+ audioProcess: null,
49
+ armTimeout: null,
50
+ pauseTimeout: null,
51
+ triggerTimeout: null,
52
+ doubleKnockTimeout: null,
53
+ resetTimeout: null,
54
+ trippedMotionSensorInterval: null,
55
+ triggeredMotionSensorInterval: null,
56
+ ...overrides,
57
+ };
58
+ }
59
+ function makeOptions(overrides = {}) {
60
+ return {
61
+ overrideOff: false,
62
+ doubleKnock: false,
63
+ doubleKnockSeconds: 90,
64
+ doubleKnockModes: [],
65
+ triggerSeconds: 0,
66
+ homeTriggerSeconds: null,
67
+ awayTriggerSeconds: null,
68
+ nightTriggerSeconds: null,
69
+ modeAwayExtendedSwitchTriggerSeconds: null,
70
+ trippedMotionSensor: false,
71
+ trippedMotionSensorSeconds: 5,
72
+ homeDoubleKnockSeconds: null,
73
+ awayDoubleKnockSeconds: null,
74
+ nightDoubleKnockSeconds: null,
75
+ ...overrides,
76
+ };
77
+ }
78
+ // ── TripHandler tests ─────────────────────────────────────────────────────────
79
+ describe('TripHandler', async () => {
80
+ const { TripHandler } = await import('../handlers/trip-handler.js');
81
+ const { EventBusService } = await import('../services/event-bus-service.js');
82
+ let state;
83
+ let services;
84
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
85
+ let tripHandler;
86
+ const mockStateHandler = {
87
+ setCurrentState: vi.fn(),
88
+ updateTargetState: vi.fn(),
89
+ resetTimers: vi.fn(),
90
+ getArmingSeconds: vi.fn().mockReturnValue(0),
91
+ };
92
+ const mockSensorHandler = {
93
+ pulseTrippedMotionSensor: vi.fn(),
94
+ resetTrippedMotionSensor: vi.fn(),
95
+ };
96
+ const mockAudio = { stop: vi.fn(), play: vi.fn(), attachToBus: vi.fn() };
97
+ beforeEach(() => {
98
+ vi.clearAllMocks();
99
+ state = makeState({ currentState: SecurityState.HOME });
100
+ services = makeServices();
101
+ const bus = new EventBusService();
102
+ const mockLog = { info: vi.fn(), warn: vi.fn(), error: vi.fn(), debug: vi.fn() };
103
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
104
+ tripHandler = new TripHandler(services, state, makeOptions(), {}, mockLog, bus, mockAudio, mockSensorHandler);
105
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
106
+ tripHandler.setStateHandler(mockStateHandler);
107
+ });
108
+ it('blocks trip when system is disarmed (not overriding)', () => {
109
+ state.currentState = SecurityState.OFF;
110
+ const result = tripHandler.updateTripSwitch(true, OriginType.REGULAR_SWITCH, false);
111
+ expect(result).toBe(false);
112
+ });
113
+ it('blocks trip when arming is in progress', () => {
114
+ state.isArming = true;
115
+ const result = tripHandler.updateTripSwitch(true, OriginType.REGULAR_SWITCH, false);
116
+ expect(result).toBe(false);
117
+ });
118
+ it('blocks trip when already triggered', () => {
119
+ state.currentState = SecurityState.TRIGGERED;
120
+ const result = tripHandler.updateTripSwitch(true, OriginType.REGULAR_SWITCH, false);
121
+ expect(result).toBe(false);
122
+ });
123
+ it('blocks trip when trigger timeout is already running', () => {
124
+ state.triggerTimeout = setTimeout(() => { }, 99999);
125
+ const result = tripHandler.updateTripSwitch(true, OriginType.REGULAR_SWITCH, false);
126
+ expect(result).toBe(false);
127
+ clearTimeout(state.triggerTimeout);
128
+ });
129
+ it('allows trip when system is armed (HOME mode)', () => {
130
+ state.currentState = SecurityState.HOME;
131
+ const result = tripHandler.updateTripSwitch(true, OriginType.REGULAR_SWITCH, false);
132
+ expect(result).toBe(true);
133
+ });
134
+ it('cancels trip and stops audio', () => {
135
+ tripHandler.updateTripSwitch(false, OriginType.REGULAR_SWITCH, false);
136
+ expect(mockAudio.stop).toHaveBeenCalled();
137
+ expect(mockStateHandler.resetTimers).toHaveBeenCalled();
138
+ });
139
+ it('disarms when trip cancelled while triggered and stateChanged=false', () => {
140
+ state.currentState = SecurityState.TRIGGERED;
141
+ tripHandler.updateTripSwitch(false, OriginType.REGULAR_SWITCH, false);
142
+ expect(mockStateHandler.updateTargetState).toHaveBeenCalledWith(SecurityState.OFF, OriginType.INTERNAL, 0);
143
+ });
144
+ it('does not disarm when stateChanged=true', () => {
145
+ state.currentState = SecurityState.TRIGGERED;
146
+ tripHandler.updateTripSwitch(false, OriginType.INTERNAL, true);
147
+ expect(mockStateHandler.updateTargetState).not.toHaveBeenCalled();
148
+ });
149
+ it('triggerIfModeSet allows when current mode matches required', () => {
150
+ state.currentState = SecurityState.HOME;
151
+ const result = tripHandler.triggerIfModeSet(SecurityState.HOME, true);
152
+ expect(result).toBe(true);
153
+ });
154
+ it('triggerIfModeSet blocks when current mode does not match', () => {
155
+ state.currentState = SecurityState.AWAY;
156
+ const result = tripHandler.triggerIfModeSet(SecurityState.HOME, true);
157
+ expect(result).toBe(false);
158
+ });
159
+ });
160
+ //# sourceMappingURL=trip-handler.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trip-handler.test.js","sourceRoot":"","sources":["../../src/tests/trip-handler.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import { EventType } from './event-type.js';
2
+ import type { TargetChangedPayload, CurrentChangedPayload, ArmingPayload, WarningPayload } from './event-type.js';
3
+ /** Maps each EventType to the payload type emitted with it. */
4
+ export type EventPayloadMap = {
5
+ [EventType.TARGET_CHANGED]: TargetChangedPayload;
6
+ [EventType.CURRENT_CHANGED]: CurrentChangedPayload;
7
+ [EventType.ARMING]: ArmingPayload;
8
+ [EventType.WARNING]: WarningPayload;
9
+ };
@@ -0,0 +1,2 @@
1
+ import { EventType } from './event-type.js';
2
+ //# sourceMappingURL=event-payload-map-type.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-payload-map-type.js","sourceRoot":"","sources":["../../src/types/event-payload-map-type.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC"}
@@ -0,0 +1,24 @@
1
+ import type { SecurityState } from './security-state-type.js';
2
+ import type { OriginType } from './origin-type.js';
3
+ /** All domain events emitted on the EventBusService. */
4
+ export declare enum EventType {
5
+ TARGET_CHANGED = "target-changed",
6
+ CURRENT_CHANGED = "current-changed",
7
+ ARMING = "arming",
8
+ WARNING = "warning"
9
+ }
10
+ export interface TargetChangedPayload {
11
+ state: SecurityState;
12
+ origin: OriginType;
13
+ }
14
+ export interface CurrentChangedPayload {
15
+ state: SecurityState;
16
+ origin: OriginType;
17
+ }
18
+ export interface ArmingPayload {
19
+ state: SecurityState;
20
+ }
21
+ export interface WarningPayload {
22
+ origin: OriginType;
23
+ triggerSeconds: number;
24
+ }
@@ -0,0 +1,9 @@
1
+ /** All domain events emitted on the EventBusService. */
2
+ export var EventType;
3
+ (function (EventType) {
4
+ EventType["TARGET_CHANGED"] = "target-changed";
5
+ EventType["CURRENT_CHANGED"] = "current-changed";
6
+ EventType["ARMING"] = "arming";
7
+ EventType["WARNING"] = "warning";
8
+ })(EventType || (EventType = {}));
9
+ //# sourceMappingURL=event-type.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-type.js","sourceRoot":"","sources":["../../src/types/event-type.ts"],"names":[],"mappings":"AAGA,wDAAwD;AACxD,MAAM,CAAN,IAAY,SAKX;AALD,WAAY,SAAS;IACnB,8CAAiC,CAAA;IACjC,gDAAmC,CAAA;IACnC,8BAAiB,CAAA;IACjB,gCAAmB,CAAA;AACrB,CAAC,EALW,SAAS,KAAT,SAAS,QAKpB"}
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Human-readable mode strings used in commands, webhooks, and audio filenames.
3
+ */
4
+ export type Mode = 'off' | 'home' | 'away' | 'night' | 'triggered' | 'warning' | 'lock' | 'unknown';
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=mode-type.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mode-type.js","sourceRoot":"","sources":["../../src/types/mode-type.ts"],"names":[],"mappings":""}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Identifies the source of a state change or trip action.
3
+ */
4
+ export declare enum OriginType {
5
+ REGULAR_SWITCH = 0,
6
+ OVERRIDE_SWITCH = 1,
7
+ INTERNAL = 3,
8
+ EXTERNAL = 4
9
+ }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Identifies the source of a state change or trip action.
3
+ */
4
+ export var OriginType;
5
+ (function (OriginType) {
6
+ OriginType[OriginType["REGULAR_SWITCH"] = 0] = "REGULAR_SWITCH";
7
+ OriginType[OriginType["OVERRIDE_SWITCH"] = 1] = "OVERRIDE_SWITCH";
8
+ OriginType[OriginType["INTERNAL"] = 3] = "INTERNAL";
9
+ OriginType[OriginType["EXTERNAL"] = 4] = "EXTERNAL";
10
+ })(OriginType || (OriginType = {}));
11
+ //# sourceMappingURL=origin-type.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"origin-type.js","sourceRoot":"","sources":["../../src/types/origin-type.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,CAAN,IAAY,UAKX;AALD,WAAY,UAAU;IACpB,+DAAkB,CAAA;IAClB,iEAAmB,CAAA;IACnB,mDAAY,CAAA;IACZ,mDAAY,CAAA;AACd,CAAC,EALW,UAAU,KAAV,UAAU,QAKrB"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Numeric states matching HomeKit's SecuritySystemCurrentState &
3
+ * SecuritySystemTargetState characteristic values.
4
+ */
5
+ export declare enum SecurityState {
6
+ HOME = 0,// STAY_ARM
7
+ AWAY = 1,// AWAY_ARM
8
+ NIGHT = 2,// NIGHT_ARM
9
+ OFF = 3,// DISARMED / DISARM
10
+ TRIGGERED = 4
11
+ }
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Numeric states matching HomeKit's SecuritySystemCurrentState &
3
+ * SecuritySystemTargetState characteristic values.
4
+ */
5
+ export var SecurityState;
6
+ (function (SecurityState) {
7
+ SecurityState[SecurityState["HOME"] = 0] = "HOME";
8
+ SecurityState[SecurityState["AWAY"] = 1] = "AWAY";
9
+ SecurityState[SecurityState["NIGHT"] = 2] = "NIGHT";
10
+ SecurityState[SecurityState["OFF"] = 3] = "OFF";
11
+ SecurityState[SecurityState["TRIGGERED"] = 4] = "TRIGGERED";
12
+ })(SecurityState || (SecurityState = {}));
13
+ //# sourceMappingURL=security-state-type.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"security-state-type.js","sourceRoot":"","sources":["../../src/types/security-state-type.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,CAAN,IAAY,aAMX;AAND,WAAY,aAAa;IACvB,iDAAQ,CAAA;IACR,iDAAQ,CAAA;IACR,mDAAS,CAAA;IACT,+CAAO,CAAA;IACP,2DAAa,CAAA;AACf,CAAC,EANW,aAAa,KAAb,aAAa,QAMxB"}
@@ -0,0 +1,4 @@
1
+ import type { Logging } from 'homebridge';
2
+ import type { SecuritySystemOptions } from '../interfaces/options-interface.js';
3
+ /** Wraps the homebridge logger to also append messages to a rotating daily log file. */
4
+ export declare function attachFileLogger(log: Logging, options: SecuritySystemOptions): void;
@@ -0,0 +1,47 @@
1
+ import fs from 'fs';
2
+ /** Wraps the homebridge logger to also append messages to a rotating daily log file. */
3
+ export function attachFileLogger(log, options) {
4
+ if (!options.logDirectory) {
5
+ return;
6
+ }
7
+ const dir = options.logDirectory;
8
+ const appendToFile = async (message) => {
9
+ const logPath = `${dir}/securitysystem.log`;
10
+ try {
11
+ const stats = await fs.promises.stat(logPath);
12
+ const today = new Date().toLocaleDateString();
13
+ if (stats.birthtime.toLocaleDateString() !== today) {
14
+ const rotated = `${dir}/securitysystem-${stats.birthtime.toLocaleDateString().replaceAll('/', '-')}.log`;
15
+ await fs.promises.rename(logPath, rotated);
16
+ }
17
+ }
18
+ catch {
19
+ // No previous log file — first write will create it.
20
+ }
21
+ try {
22
+ const line = `[${new Date().toLocaleString()}] ${message}\n`;
23
+ await fs.promises.appendFile(logPath, line, { flag: 'a' });
24
+ }
25
+ catch (err) {
26
+ // Avoid infinite recursion — call the original methods directly.
27
+ process.stderr.write(`File logger error: ${err}\n`);
28
+ }
29
+ };
30
+ const origInfo = log.info.bind(log);
31
+ const origWarn = log.warn.bind(log);
32
+ const origError = log.error.bind(log);
33
+ // Re-assign to also write to file.
34
+ log.info = (msg) => {
35
+ origInfo(msg);
36
+ appendToFile(msg);
37
+ };
38
+ log.warn = (msg) => {
39
+ origWarn(msg);
40
+ appendToFile(msg);
41
+ };
42
+ log.error = (msg) => {
43
+ origError(msg);
44
+ appendToFile(msg);
45
+ };
46
+ }
47
+ //# sourceMappingURL=log-util.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"log-util.js","sourceRoot":"","sources":["../../src/utils/log-util.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAC;AAIpB,wFAAwF;AACxF,MAAM,UAAU,gBAAgB,CAAC,GAAY,EAAE,OAA8B;IAC3E,IAAI,CAAC,OAAO,CAAC,YAAY,EAAE,CAAC;QAC1B,OAAO;IACT,CAAC;IAED,MAAM,GAAG,GAAG,OAAO,CAAC,YAAY,CAAC;IAEjC,MAAM,YAAY,GAAG,KAAK,EAAE,OAAe,EAAiB,EAAE;QAC5D,MAAM,OAAO,GAAG,GAAG,GAAG,qBAAqB,CAAC;QAE5C,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAC9C,MAAM,KAAK,GAAG,IAAI,IAAI,EAAE,CAAC,kBAAkB,EAAE,CAAC;YAE9C,IAAI,KAAK,CAAC,SAAS,CAAC,kBAAkB,EAAE,KAAK,KAAK,EAAE,CAAC;gBACnD,MAAM,OAAO,GAAG,GAAG,GAAG,mBAAmB,KAAK,CAAC,SAAS,CAAC,kBAAkB,EAAE,CAAC,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,MAAM,CAAC;gBACzG,MAAM,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;YAC7C,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,qDAAqD;QACvD,CAAC;QAED,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,IAAI,IAAI,IAAI,EAAE,CAAC,cAAc,EAAE,KAAK,OAAO,IAAI,CAAC;YAC7D,MAAM,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,OAAO,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC;QAC7D,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,iEAAiE;YACjE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,sBAAsB,GAAG,IAAI,CAAC,CAAC;QACtD,CAAC;IACH,CAAC,CAAC;IAEF,MAAM,QAAQ,GAAG,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACpC,MAAM,QAAQ,GAAG,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACpC,MAAM,SAAS,GAAG,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAEtC,mCAAmC;IAClC,GAA0C,CAAC,IAAI,GAAG,CAAC,GAAW,EAAE,EAAE;QACjE,QAAQ,CAAC,GAAG,CAAC,CAAC;QACd,YAAY,CAAC,GAAG,CAAC,CAAC;IACpB,CAAC,CAAC;IACD,GAA0C,CAAC,IAAI,GAAG,CAAC,GAAW,EAAE,EAAE;QACjE,QAAQ,CAAC,GAAG,CAAC,CAAC;QACd,YAAY,CAAC,GAAG,CAAC,CAAC;IACpB,CAAC,CAAC;IACD,GAA0C,CAAC,KAAK,GAAG,CAAC,GAAW,EAAE,EAAE;QAClE,SAAS,CAAC,GAAG,CAAC,CAAC;QACf,YAAY,CAAC,GAAG,CAAC,CAAC;IACpB,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,6 @@
1
+ import type { Logging } from 'homebridge';
2
+ import type { SecuritySystemOptions } from '../interfaces/options-interface.js';
3
+ type RawConfig = Record<string, unknown>;
4
+ /** Parse, validate and normalise raw homebridge config into a typed options object. */
5
+ export declare function parseOptions(log: Logging, raw: RawConfig): SecuritySystemOptions;
6
+ export {};