homebridge-securitysystem 11.3.0 → 11.3.1-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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,24 @@
1
1
  # Changelog
2
2
 
3
+ ## v11.3.0 - 2026-06-12
4
+
5
+ <!-- Release notes generated using configuration in .github/release.yml at v11.3.0 -->
6
+
7
+ ## What's Changed
8
+ ### ✨ Enhancements
9
+ * Config schema update by @jeffreyfrei in https://github.com/MiguelRipoll23/homebridge-securitysystem/pull/868
10
+ ### 📦 Dependencies
11
+ * build(deps-dev): bump homebridge from 2.0.2 to 2.1.0 by @dependabot[bot] in https://github.com/MiguelRipoll23/homebridge-securitysystem/pull/867
12
+ * build(deps): bump MiguelRipoll23/get-next-version from 3.0.0 to 3.1.0 by @dependabot[bot] in https://github.com/MiguelRipoll23/homebridge-securitysystem/pull/869
13
+ * build(deps): bump MiguelRipoll23/get-next-version from 3.1.0 to 3.2.0 by @dependabot[bot] in https://github.com/MiguelRipoll23/homebridge-securitysystem/pull/870
14
+ * build(deps): bump github/gh-aw-actions from 0.78.1 to 0.78.3 by @dependabot[bot] in https://github.com/MiguelRipoll23/homebridge-securitysystem/pull/871
15
+
16
+ ## New Contributors
17
+ * @jeffreyfrei made their first contribution in https://github.com/MiguelRipoll23/homebridge-securitysystem/pull/868
18
+
19
+ **Full Changelog**: https://github.com/MiguelRipoll23/homebridge-securitysystem/compare/v11.2.0...v11.3.0
20
+
21
+
3
22
  ## v11.3.0-beta.1 - 2026-06-11
4
23
 
5
24
  <!-- Release notes generated using configuration in .github/release.yml at v11.3.0-beta.1 -->
@@ -91,13 +91,21 @@ export class SecuritySystem {
91
91
  this.serviceList = buildServiceList(this.svcs, this.options, this.state);
92
92
  // Startup tasks.
93
93
  this.logStartup();
94
+ const syncModeSwitches = () => {
95
+ this.bus.emit(EventType.RESET_MODE_SWITCHES, {});
96
+ this.bus.emit(EventType.UPDATE_MODE_SWITCHES, {});
97
+ };
94
98
  if (this.options.saveState) {
95
99
  this.storageService.init().then(() => this.storageService.load(this.state).then(() => {
96
100
  this.svcs.mainService.updateCharacteristic(Char.SecuritySystemTargetState, this.state.targetState);
97
101
  this.svcs.mainService.updateCharacteristic(Char.SecuritySystemCurrentState, this.state.currentState);
98
102
  this.stateHandler.logMode('Current', this.state.currentState);
103
+ syncModeSwitches();
99
104
  }));
100
105
  }
106
+ else {
107
+ syncModeSwitches();
108
+ }
101
109
  if (this.options.audioPath) {
102
110
  this.audioService.setup();
103
111
  }
@@ -1 +1 @@
1
- {"version":3,"file":"security-system.js","sourceRoot":"","sources":["../src/security-system.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"security-system.js","sourceRoot":"","sources":["../src/security-system.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,267 @@
1
+ import { describe, it, expect, vi } from 'vitest';
2
+ import { SecurityState } from '../types/security-state-type.js';
3
+ // ── Minimal mocks ─────────────────────────────────────────────────────────────
4
+ function makeMockCharacteristic(value = false) {
5
+ const characteristic = { value, updateValue: vi.fn(), setProps: vi.fn() };
6
+ characteristic.updateValue.mockImplementation((v) => {
7
+ characteristic.value = v;
8
+ });
9
+ return characteristic;
10
+ }
11
+ function makeMockService(characteristicValue = false) {
12
+ const characteristic = makeMockCharacteristic(characteristicValue);
13
+ const service = {
14
+ getCharacteristic: vi.fn().mockReturnValue(characteristic),
15
+ updateCharacteristic: vi.fn((_name, value) => {
16
+ characteristic.value = value;
17
+ return service;
18
+ }),
19
+ setCharacteristic: vi.fn().mockReturnThis(),
20
+ addCharacteristic: vi.fn(),
21
+ addOptionalCharacteristic: vi.fn(),
22
+ };
23
+ return service;
24
+ }
25
+ function makeServices() {
26
+ const keys = [
27
+ 'mainService', 'accessoryInfoService', 'tripSwitchService', 'tripHomeSwitchService',
28
+ 'tripAwaySwitchService', 'tripNightSwitchService', 'tripOverrideSwitchService',
29
+ 'armingLockSwitchService', 'armingLockHomeSwitchService', 'armingLockAwaySwitchService',
30
+ 'armingLockNightSwitchService', 'modeHomeSwitchService', 'modeAwaySwitchService',
31
+ 'modeNightSwitchService', 'modeOffSwitchService', 'modeAwayExtendedSwitchService',
32
+ 'modePauseSwitchService', 'audioSwitchService', 'armingMotionSensorService',
33
+ 'trippedMotionSensorService', 'triggeredMotionSensorService', 'triggeredResetMotionSensorService',
34
+ ];
35
+ const registry = {};
36
+ for (const key of keys) {
37
+ registry[key] = makeMockService();
38
+ }
39
+ registry.customTripHomeSwitchServices = [];
40
+ registry.customTripAwaySwitchServices = [];
41
+ registry.customTripNightSwitchServices = [];
42
+ return registry;
43
+ }
44
+ function makeState(overrides = {}) {
45
+ return {
46
+ currentState: SecurityState.OFF,
47
+ targetState: SecurityState.OFF,
48
+ defaultState: SecurityState.OFF,
49
+ availableTargetStates: [SecurityState.HOME, SecurityState.AWAY, SecurityState.NIGHT, SecurityState.OFF],
50
+ isArming: false,
51
+ isTripping: false,
52
+ isKnocked: false,
53
+ serverAuthenticationAttempts: 0,
54
+ pausedCurrentState: null,
55
+ audioProcess: 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
+ overrideOff: false,
68
+ doubleKnock: false,
69
+ doubleKnockSeconds: 90,
70
+ doubleKnockModes: [],
71
+ homeTriggerSeconds: null,
72
+ awayTriggerSeconds: null,
73
+ nightTriggerSeconds: null,
74
+ homeDoubleKnockSeconds: null,
75
+ awayDoubleKnockSeconds: null,
76
+ nightDoubleKnockSeconds: null,
77
+ modeAwayExtendedSwitchTriggerSeconds: null,
78
+ armingLockSwitch: false,
79
+ armingLockSwitches: false,
80
+ disabledModes: [],
81
+ homeArmSeconds: null,
82
+ awayArmSeconds: null,
83
+ nightArmSeconds: null,
84
+ triggeredMotionSensor: false,
85
+ triggeredMotionSensorSeconds: 5,
86
+ trippedMotionSensor: false,
87
+ trippedMotionSensorSeconds: 5,
88
+ resetOffFlow: false,
89
+ ...overrides,
90
+ };
91
+ }
92
+ function makeMockLog() {
93
+ return { info: vi.fn(), warn: vi.fn(), error: vi.fn(), debug: vi.fn() };
94
+ }
95
+ function makeMockStateHandler() {
96
+ return {
97
+ updateTargetState: vi.fn(),
98
+ getArmingSeconds: vi.fn().mockReturnValue(0),
99
+ };
100
+ }
101
+ function makeMockTimers() {
102
+ return {
103
+ setArmTimer: vi.fn(), clearArmTimer: vi.fn(),
104
+ setTriggerTimer: vi.fn(), clearTriggerTimer: vi.fn(), isTriggerRunning: vi.fn().mockReturnValue(false),
105
+ setPauseTimer: vi.fn(), clearPauseTimer: vi.fn(),
106
+ setDoubleKnockTimer: vi.fn(), clearDoubleKnockTimer: vi.fn(),
107
+ setResetTimer: vi.fn(), clearResetTimer: vi.fn(),
108
+ setTrippedInterval: vi.fn(), clearTrippedInterval: vi.fn(),
109
+ setTriggeredInterval: vi.fn(), clearTriggeredInterval: vi.fn(),
110
+ clearAll: vi.fn(),
111
+ };
112
+ }
113
+ // ── SwitchHandler tests ───────────────────────────────────────────────────────
114
+ describe('SwitchHandler.updateModeSwitches', async () => {
115
+ const { SwitchHandler } = await import('../handlers/switch-handler.js');
116
+ it('sets mode OFF switch ON when targetState is OFF', () => {
117
+ const services = makeServices();
118
+ const state = makeState({ targetState: SecurityState.OFF });
119
+ const handler = new SwitchHandler(services, state, makeOptions(), {}, makeMockLog(), makeMockTimers(), makeMockStateHandler());
120
+ const offCharacteristic = services.modeOffSwitchService.getCharacteristic('On');
121
+ handler.updateModeSwitches();
122
+ expect(offCharacteristic.value).toBe(true);
123
+ });
124
+ it('sets mode HOME switch ON when targetState is HOME', () => {
125
+ const services = makeServices();
126
+ const state = makeState({ targetState: SecurityState.HOME });
127
+ const handler = new SwitchHandler(services, state, makeOptions(), {}, makeMockLog(), makeMockTimers(), makeMockStateHandler());
128
+ handler.updateModeSwitches();
129
+ expect(services.modeHomeSwitchService.getCharacteristic('On').value).toBe(true);
130
+ });
131
+ it('sets mode AWAY switch ON when targetState is AWAY', () => {
132
+ const services = makeServices();
133
+ const state = makeState({ targetState: SecurityState.AWAY });
134
+ const handler = new SwitchHandler(services, state, makeOptions(), {}, makeMockLog(), makeMockTimers(), makeMockStateHandler());
135
+ handler.updateModeSwitches();
136
+ expect(services.modeAwaySwitchService.getCharacteristic('On').value).toBe(true);
137
+ });
138
+ it('sets mode NIGHT switch ON when targetState is NIGHT', () => {
139
+ const services = makeServices();
140
+ const state = makeState({ targetState: SecurityState.NIGHT });
141
+ const handler = new SwitchHandler(services, state, makeOptions(), {}, makeMockLog(), makeMockTimers(), makeMockStateHandler());
142
+ handler.updateModeSwitches();
143
+ expect(services.modeNightSwitchService.getCharacteristic('On').value).toBe(true);
144
+ });
145
+ it('does not turn on any mode switch when targetState is TRIGGERED', () => {
146
+ const services = makeServices();
147
+ const state = makeState({ targetState: SecurityState.TRIGGERED });
148
+ const handler = new SwitchHandler(services, state, makeOptions(), {}, makeMockLog(), makeMockTimers(), makeMockStateHandler());
149
+ const modeServices = [
150
+ services.modeHomeSwitchService, services.modeAwaySwitchService,
151
+ services.modeNightSwitchService, services.modeOffSwitchService,
152
+ services.modeAwayExtendedSwitchService, services.modePauseSwitchService,
153
+ ];
154
+ handler.updateModeSwitches();
155
+ for (const service of modeServices) {
156
+ expect(service.updateCharacteristic).not.toHaveBeenCalled();
157
+ }
158
+ });
159
+ it('updates characteristic via updateCharacteristic (HomeKit compliant)', () => {
160
+ const services = makeServices();
161
+ const state = makeState({ targetState: SecurityState.OFF });
162
+ const Characteristic = { On: 'On' };
163
+ const handler = new SwitchHandler(services, state, makeOptions(), Characteristic, makeMockLog(), makeMockTimers(), makeMockStateHandler());
164
+ handler.updateModeSwitches();
165
+ expect(services.modeOffSwitchService.updateCharacteristic).toHaveBeenCalledWith('On', true);
166
+ });
167
+ });
168
+ describe('SwitchHandler.resetModeSwitches', async () => {
169
+ const { SwitchHandler } = await import('../handlers/switch-handler.js');
170
+ it('turns OFF all mode switches that are ON', () => {
171
+ const services = makeServices();
172
+ const state = makeState();
173
+ const handler = new SwitchHandler(services, state, makeOptions(), {}, makeMockLog(), makeMockTimers(), makeMockStateHandler());
174
+ const modeServiceKeys = [
175
+ 'modeHomeSwitchService', 'modeAwaySwitchService', 'modeNightSwitchService',
176
+ 'modeOffSwitchService', 'modeAwayExtendedSwitchService', 'modePauseSwitchService',
177
+ ];
178
+ for (const key of modeServiceKeys) {
179
+ services[key].getCharacteristic('On').value = true;
180
+ }
181
+ handler.resetModeSwitches();
182
+ for (const key of modeServiceKeys) {
183
+ expect(services[key].getCharacteristic('On').value).toBe(false);
184
+ }
185
+ });
186
+ it('does not call updateValue on switches that are already OFF', () => {
187
+ const services = makeServices();
188
+ const state = makeState();
189
+ const handler = new SwitchHandler(services, state, makeOptions(), {}, makeMockLog(), makeMockTimers(), makeMockStateHandler());
190
+ const offCharacteristic = services.modeOffSwitchService.getCharacteristic('On');
191
+ offCharacteristic.value = false;
192
+ handler.resetModeSwitches();
193
+ expect(offCharacteristic.updateValue).not.toHaveBeenCalled();
194
+ });
195
+ });
196
+ describe('SwitchHandler.subscribeToStateEvents', async () => {
197
+ const { SwitchHandler } = await import('../handlers/switch-handler.js');
198
+ const { EventBusService } = await import('../services/event-bus-service.js');
199
+ const { EventType } = await import('../types/event-type.js');
200
+ it('calls updateModeSwitches on UPDATE_MODE_SWITCHES event', () => {
201
+ const bus = new EventBusService();
202
+ const state = makeState({ targetState: SecurityState.HOME });
203
+ const services = makeServices();
204
+ const handler = new SwitchHandler(services, state, makeOptions(), {}, makeMockLog(), makeMockTimers(), makeMockStateHandler());
205
+ handler.subscribeToStateEvents(bus);
206
+ bus.emit(EventType.UPDATE_MODE_SWITCHES, {});
207
+ expect(services.modeHomeSwitchService.getCharacteristic('On').value).toBe(true);
208
+ });
209
+ it('calls resetModeSwitches on RESET_MODE_SWITCHES event', () => {
210
+ const bus = new EventBusService();
211
+ const state = makeState();
212
+ const services = makeServices();
213
+ const handler = new SwitchHandler(services, state, makeOptions(), {}, makeMockLog(), makeMockTimers(), makeMockStateHandler());
214
+ const modeServiceKeys = [
215
+ 'modeHomeSwitchService', 'modeAwaySwitchService', 'modeNightSwitchService',
216
+ 'modeOffSwitchService', 'modeAwayExtendedSwitchService', 'modePauseSwitchService',
217
+ ];
218
+ for (const key of modeServiceKeys) {
219
+ services[key].getCharacteristic('On').value = true;
220
+ }
221
+ handler.subscribeToStateEvents(bus);
222
+ bus.emit(EventType.RESET_MODE_SWITCHES, {});
223
+ for (const key of modeServiceKeys) {
224
+ expect(services[key].getCharacteristic('On').value).toBe(false);
225
+ }
226
+ });
227
+ });
228
+ // ── Regression: mode switch sync on startup ──────────────────────────────────
229
+ describe('SwitchHandler startup sync regression', async () => {
230
+ const { SwitchHandler } = await import('../handlers/switch-handler.js');
231
+ it('sets mode OFF switch ON when state is initialized to OFF (regression test for #889)', () => {
232
+ const services = makeServices();
233
+ const state = makeState({ targetState: SecurityState.OFF });
234
+ const handler = new SwitchHandler(services, state, makeOptions(), {}, makeMockLog(), makeMockTimers(), makeMockStateHandler());
235
+ expect(services.modeOffSwitchService.getCharacteristic('On').value).toBe(false);
236
+ handler.updateModeSwitches();
237
+ expect(services.modeOffSwitchService.getCharacteristic('On').value).toBe(true);
238
+ expect(services.modeHomeSwitchService.getCharacteristic('On').value).toBe(false);
239
+ expect(services.modeAwaySwitchService.getCharacteristic('On').value).toBe(false);
240
+ expect(services.modeNightSwitchService.getCharacteristic('On').value).toBe(false);
241
+ });
242
+ it('sets mode HOME switch ON when state is initialized to HOME', () => {
243
+ const services = makeServices();
244
+ const state = makeState({ targetState: SecurityState.HOME });
245
+ const handler = new SwitchHandler(services, state, makeOptions(), {}, makeMockLog(), makeMockTimers(), makeMockStateHandler());
246
+ handler.updateModeSwitches();
247
+ expect(services.modeHomeSwitchService.getCharacteristic('On').value).toBe(true);
248
+ expect(services.modeOffSwitchService.getCharacteristic('On').value).toBe(false);
249
+ });
250
+ it('sets mode AWAY switch ON when state is initialized to AWAY', () => {
251
+ const services = makeServices();
252
+ const state = makeState({ targetState: SecurityState.AWAY });
253
+ const handler = new SwitchHandler(services, state, makeOptions(), {}, makeMockLog(), makeMockTimers(), makeMockStateHandler());
254
+ handler.updateModeSwitches();
255
+ expect(services.modeAwaySwitchService.getCharacteristic('On').value).toBe(true);
256
+ expect(services.modeOffSwitchService.getCharacteristic('On').value).toBe(false);
257
+ });
258
+ it('sets mode NIGHT switch ON when state is initialized to NIGHT', () => {
259
+ const services = makeServices();
260
+ const state = makeState({ targetState: SecurityState.NIGHT });
261
+ const handler = new SwitchHandler(services, state, makeOptions(), {}, makeMockLog(), makeMockTimers(), makeMockStateHandler());
262
+ handler.updateModeSwitches();
263
+ expect(services.modeNightSwitchService.getCharacteristic('On').value).toBe(true);
264
+ expect(services.modeOffSwitchService.getCharacteristic('On').value).toBe(false);
265
+ });
266
+ });
267
+ //# sourceMappingURL=switch-handler.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"switch-handler.test.js","sourceRoot":"","sources":["../../src/tests/switch-handler.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAC;AAKhE,iFAAiF;AAEjF,SAAS,sBAAsB,CAAC,QAAiB,KAAK;IACpD,MAAM,cAAc,GAAG,EAAE,KAAK,EAAE,WAAW,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC;IAC1E,cAAc,CAAC,WAAW,CAAC,kBAAkB,CAAC,CAAC,CAAU,EAAE,EAAE;QAC3D,cAAc,CAAC,KAAK,GAAG,CAAC,CAAC;IAC3B,CAAC,CAAC,CAAC;IACH,OAAO,cAAc,CAAC;AACxB,CAAC;AAED,SAAS,eAAe,CAAC,sBAA+B,KAAK;IAC3D,MAAM,cAAc,GAAG,sBAAsB,CAAC,mBAAmB,CAAC,CAAC;IACnE,MAAM,OAAO,GAAG;QACd,iBAAiB,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC,cAAc,CAAC;QAC1D,oBAAoB,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,KAAc,EAAE,KAAc,EAAE,EAAE;YAC7D,cAAc,CAAC,KAAK,GAAG,KAAK,CAAC;YAC7B,OAAO,OAAO,CAAC;QACjB,CAAC,CAAC;QACF,iBAAiB,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,cAAc,EAAE;QAC3C,iBAAiB,EAAE,EAAE,CAAC,EAAE,EAAE;QAC1B,yBAAyB,EAAE,EAAE,CAAC,EAAE,EAAE;KACnC,CAAC;IACF,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,SAAS,YAAY;IACnB,MAAM,IAAI,GAAG;QACX,aAAa,EAAE,sBAAsB,EAAE,mBAAmB,EAAE,uBAAuB;QACnF,uBAAuB,EAAE,wBAAwB,EAAE,2BAA2B;QAC9E,yBAAyB,EAAE,6BAA6B,EAAE,6BAA6B;QACvF,8BAA8B,EAAE,uBAAuB,EAAE,uBAAuB;QAChF,wBAAwB,EAAE,sBAAsB,EAAE,+BAA+B;QACjF,wBAAwB,EAAE,oBAAoB,EAAE,2BAA2B;QAC3E,4BAA4B,EAAE,8BAA8B,EAAE,mCAAmC;KAClG,CAAC;IACF,MAAM,QAAQ,GAAmE,EAAE,CAAC;IACpF,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,QAAQ,CAAC,GAAG,CAAC,GAAG,eAAe,EAAE,CAAC;IACpC,CAAC;IACD,QAAQ,CAAC,4BAA4B,GAAG,EAAE,CAAC;IAC3C,QAAQ,CAAC,4BAA4B,GAAG,EAAE,CAAC;IAC3C,QAAQ,CAAC,6BAA6B,GAAG,EAAE,CAAC;IAC5C,OAAO,QAAsC,CAAC;AAChD,CAAC;AAED,SAAS,SAAS,CAAC,YAAkC,EAAE;IACrD,OAAO;QACL,YAAY,EAAE,aAAa,CAAC,GAAG;QAC/B,WAAW,EAAE,aAAa,CAAC,GAAG;QAC9B,YAAY,EAAE,aAAa,CAAC,GAAG;QAC/B,qBAAqB,EAAE,CAAC,aAAa,CAAC,IAAI,EAAE,aAAa,CAAC,IAAI,EAAE,aAAa,CAAC,KAAK,EAAE,aAAa,CAAC,GAAG,CAAC;QACvG,QAAQ,EAAE,KAAK;QACf,UAAU,EAAE,KAAK;QACjB,SAAS,EAAE,KAAK;QAChB,4BAA4B,EAAE,CAAC;QAC/B,kBAAkB,EAAE,IAAI;QACxB,YAAY,EAAE,IAAI;QAClB,GAAG,SAAS;KACb,CAAC;AACJ,CAAC;AAED,SAAS,WAAW,CAAC,YAA4C,EAAE;IACjE,OAAO;QACL,UAAU,EAAE,CAAC;QACb,cAAc,EAAE,CAAC;QACjB,YAAY,EAAE,EAAE;QAChB,QAAQ,EAAE,KAAK;QACf,SAAS,EAAE,KAAK;QAChB,SAAS,EAAE,KAAK;QAChB,WAAW,EAAE,KAAK;QAClB,WAAW,EAAE,KAAK;QAClB,kBAAkB,EAAE,EAAE;QACtB,gBAAgB,EAAE,EAAE;QACpB,kBAAkB,EAAE,IAAI;QACxB,kBAAkB,EAAE,IAAI;QACxB,mBAAmB,EAAE,IAAI;QACzB,sBAAsB,EAAE,IAAI;QAC5B,sBAAsB,EAAE,IAAI;QAC5B,uBAAuB,EAAE,IAAI;QAC7B,oCAAoC,EAAE,IAAI;QAC1C,gBAAgB,EAAE,KAAK;QACvB,kBAAkB,EAAE,KAAK;QACzB,aAAa,EAAE,EAAE;QACjB,cAAc,EAAE,IAAI;QACpB,cAAc,EAAE,IAAI;QACpB,eAAe,EAAE,IAAI;QACrB,qBAAqB,EAAE,KAAK;QAC5B,4BAA4B,EAAE,CAAC;QAC/B,mBAAmB,EAAE,KAAK;QAC1B,0BAA0B,EAAE,CAAC;QAC7B,YAAY,EAAE,KAAK;QACnB,GAAG,SAAS;KACuB,CAAC;AACxC,CAAC;AAED,SAAS,WAAW;IAClB,OAAO,EAAE,IAAI,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC;AAC1E,CAAC;AAED,SAAS,oBAAoB;IAC3B,OAAO;QACL,iBAAiB,EAAE,EAAE,CAAC,EAAE,EAAE;QAC1B,gBAAgB,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC,CAAC,CAAC;KAC7C,CAAC;AACJ,CAAC;AAED,SAAS,cAAc;IACrB,OAAO;QACL,WAAW,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,aAAa,EAAE,EAAE,CAAC,EAAE,EAAE;QAC5C,eAAe,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,iBAAiB,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,gBAAgB,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC,KAAK,CAAC;QACtG,aAAa,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,eAAe,EAAE,EAAE,CAAC,EAAE,EAAE;QAChD,mBAAmB,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,qBAAqB,EAAE,EAAE,CAAC,EAAE,EAAE;QAC5D,aAAa,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,eAAe,EAAE,EAAE,CAAC,EAAE,EAAE;QAChD,kBAAkB,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,oBAAoB,EAAE,EAAE,CAAC,EAAE,EAAE;QAC1D,oBAAoB,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,sBAAsB,EAAE,EAAE,CAAC,EAAE,EAAE;QAC9D,QAAQ,EAAE,EAAE,CAAC,EAAE,EAAE;KACX,CAAC;AACX,CAAC;AAED,iFAAiF;AAEjF,QAAQ,CAAC,kCAAkC,EAAE,KAAK,IAAI,EAAE;IACtD,MAAM,EAAE,aAAa,EAAE,GAAG,MAAM,MAAM,CAAC,+BAA+B,CAAC,CAAC;IAExE,EAAE,CAAC,iDAAiD,EAAE,GAAG,EAAE;QACzD,MAAM,QAAQ,GAAG,YAAY,EAAE,CAAC;QAChC,MAAM,KAAK,GAAG,SAAS,CAAC,EAAE,WAAW,EAAE,aAAa,CAAC,GAAG,EAAE,CAAC,CAAC;QAC5D,MAAM,OAAO,GAAG,IAAI,aAAa,CAC/B,QAAQ,EAAE,KAAK,EAAE,WAAW,EAAE,EAAE,EAAS,EAAE,WAAW,EAAS,EAAE,cAAc,EAAE,EAAE,oBAAoB,EAAS,CACjH,CAAC;QACF,MAAM,iBAAiB,GAAG,QAAQ,CAAC,oBAAoB,CAAC,iBAAiB,CAAC,IAAW,CAAE,CAAC;QAExF,OAAO,CAAC,kBAAkB,EAAE,CAAC;QAE7B,MAAM,CAAC,iBAAiB,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC7C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mDAAmD,EAAE,GAAG,EAAE;QAC3D,MAAM,QAAQ,GAAG,YAAY,EAAE,CAAC;QAChC,MAAM,KAAK,GAAG,SAAS,CAAC,EAAE,WAAW,EAAE,aAAa,CAAC,IAAI,EAAE,CAAC,CAAC;QAC7D,MAAM,OAAO,GAAG,IAAI,aAAa,CAC/B,QAAQ,EAAE,KAAK,EAAE,WAAW,EAAE,EAAE,EAAS,EAAE,WAAW,EAAS,EAAE,cAAc,EAAE,EAAE,oBAAoB,EAAS,CACjH,CAAC;QAEF,OAAO,CAAC,kBAAkB,EAAE,CAAC;QAE7B,MAAM,CAAC,QAAQ,CAAC,qBAAqB,CAAC,iBAAiB,CAAC,IAAW,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACzF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mDAAmD,EAAE,GAAG,EAAE;QAC3D,MAAM,QAAQ,GAAG,YAAY,EAAE,CAAC;QAChC,MAAM,KAAK,GAAG,SAAS,CAAC,EAAE,WAAW,EAAE,aAAa,CAAC,IAAI,EAAE,CAAC,CAAC;QAC7D,MAAM,OAAO,GAAG,IAAI,aAAa,CAC/B,QAAQ,EAAE,KAAK,EAAE,WAAW,EAAE,EAAE,EAAS,EAAE,WAAW,EAAS,EAAE,cAAc,EAAE,EAAE,oBAAoB,EAAS,CACjH,CAAC;QAEF,OAAO,CAAC,kBAAkB,EAAE,CAAC;QAE7B,MAAM,CAAC,QAAQ,CAAC,qBAAqB,CAAC,iBAAiB,CAAC,IAAW,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACzF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qDAAqD,EAAE,GAAG,EAAE;QAC7D,MAAM,QAAQ,GAAG,YAAY,EAAE,CAAC;QAChC,MAAM,KAAK,GAAG,SAAS,CAAC,EAAE,WAAW,EAAE,aAAa,CAAC,KAAK,EAAE,CAAC,CAAC;QAC9D,MAAM,OAAO,GAAG,IAAI,aAAa,CAC/B,QAAQ,EAAE,KAAK,EAAE,WAAW,EAAE,EAAE,EAAS,EAAE,WAAW,EAAS,EAAE,cAAc,EAAE,EAAE,oBAAoB,EAAS,CACjH,CAAC;QAEF,OAAO,CAAC,kBAAkB,EAAE,CAAC;QAE7B,MAAM,CAAC,QAAQ,CAAC,sBAAsB,CAAC,iBAAiB,CAAC,IAAW,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1F,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gEAAgE,EAAE,GAAG,EAAE;QACxE,MAAM,QAAQ,GAAG,YAAY,EAAE,CAAC;QAChC,MAAM,KAAK,GAAG,SAAS,CAAC,EAAE,WAAW,EAAE,aAAa,CAAC,SAAS,EAAE,CAAC,CAAC;QAClE,MAAM,OAAO,GAAG,IAAI,aAAa,CAC/B,QAAQ,EAAE,KAAK,EAAE,WAAW,EAAE,EAAE,EAAS,EAAE,WAAW,EAAS,EAAE,cAAc,EAAE,EAAE,oBAAoB,EAAS,CACjH,CAAC;QACF,MAAM,YAAY,GAAG;YACnB,QAAQ,CAAC,qBAAqB,EAAE,QAAQ,CAAC,qBAAqB;YAC9D,QAAQ,CAAC,sBAAsB,EAAE,QAAQ,CAAC,oBAAoB;YAC9D,QAAQ,CAAC,6BAA6B,EAAE,QAAQ,CAAC,sBAAsB;SACxE,CAAC;QAEF,OAAO,CAAC,kBAAkB,EAAE,CAAC;QAE7B,KAAK,MAAM,OAAO,IAAI,YAAY,EAAE,CAAC;YACnC,MAAM,CAAC,OAAO,CAAC,oBAAoB,CAAC,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC;QAC9D,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qEAAqE,EAAE,GAAG,EAAE;QAC7E,MAAM,QAAQ,GAAG,YAAY,EAAE,CAAC;QAChC,MAAM,KAAK,GAAG,SAAS,CAAC,EAAE,WAAW,EAAE,aAAa,CAAC,GAAG,EAAE,CAAC,CAAC;QAC5D,MAAM,cAAc,GAAG,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;QACpC,MAAM,OAAO,GAAG,IAAI,aAAa,CAC/B,QAAQ,EAAE,KAAK,EAAE,WAAW,EAAE,EAAE,cAAqB,EAAE,WAAW,EAAS,EAAE,cAAc,EAAE,EAAE,oBAAoB,EAAS,CAC7H,CAAC;QAEF,OAAO,CAAC,kBAAkB,EAAE,CAAC;QAE7B,MAAM,CAAC,QAAQ,CAAC,oBAAoB,CAAC,oBAAoB,CAAC,CAAC,oBAAoB,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAC9F,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,iCAAiC,EAAE,KAAK,IAAI,EAAE;IACrD,MAAM,EAAE,aAAa,EAAE,GAAG,MAAM,MAAM,CAAC,+BAA+B,CAAC,CAAC;IAExE,EAAE,CAAC,yCAAyC,EAAE,GAAG,EAAE;QACjD,MAAM,QAAQ,GAAG,YAAY,EAAE,CAAC;QAChC,MAAM,KAAK,GAAG,SAAS,EAAE,CAAC;QAC1B,MAAM,OAAO,GAAG,IAAI,aAAa,CAC/B,QAAQ,EAAE,KAAK,EAAE,WAAW,EAAE,EAAE,EAAS,EAAE,WAAW,EAAS,EAAE,cAAc,EAAE,EAAE,oBAAoB,EAAS,CACjH,CAAC;QACF,MAAM,eAAe,GAAiC;YACpD,uBAAuB,EAAE,uBAAuB,EAAE,wBAAwB;YAC1E,sBAAsB,EAAE,+BAA+B,EAAE,wBAAwB;SAClF,CAAC;QACF,KAAK,MAAM,GAAG,IAAI,eAAe,EAAE,CAAC;YACjC,QAAQ,CAAC,GAAG,CAAS,CAAC,iBAAiB,CAAC,IAAW,CAAC,CAAC,KAAK,GAAG,IAAI,CAAC;QACrE,CAAC;QAED,OAAO,CAAC,iBAAiB,EAAE,CAAC;QAE5B,KAAK,MAAM,GAAG,IAAI,eAAe,EAAE,CAAC;YAClC,MAAM,CAAE,QAAQ,CAAC,GAAG,CAAS,CAAC,iBAAiB,CAAC,IAAW,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAClF,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4DAA4D,EAAE,GAAG,EAAE;QACpE,MAAM,QAAQ,GAAG,YAAY,EAAE,CAAC;QAChC,MAAM,KAAK,GAAG,SAAS,EAAE,CAAC;QAC1B,MAAM,OAAO,GAAG,IAAI,aAAa,CAC/B,QAAQ,EAAE,KAAK,EAAE,WAAW,EAAE,EAAE,EAAS,EAAE,WAAW,EAAS,EAAE,cAAc,EAAE,EAAE,oBAAoB,EAAS,CACjH,CAAC;QACF,MAAM,iBAAiB,GAAG,QAAQ,CAAC,oBAAoB,CAAC,iBAAiB,CAAC,IAAW,CAAE,CAAC;QACxF,iBAAiB,CAAC,KAAK,GAAG,KAAK,CAAC;QAEhC,OAAO,CAAC,iBAAiB,EAAE,CAAC;QAE5B,MAAM,CAAC,iBAAiB,CAAC,WAAW,CAAC,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC;IAC/D,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,sCAAsC,EAAE,KAAK,IAAI,EAAE;IAC1D,MAAM,EAAE,aAAa,EAAE,GAAG,MAAM,MAAM,CAAC,+BAA+B,CAAC,CAAC;IACxE,MAAM,EAAE,eAAe,EAAE,GAAG,MAAM,MAAM,CAAC,kCAAkC,CAAC,CAAC;IAC7E,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,MAAM,CAAC,wBAAwB,CAAC,CAAC;IAE7D,EAAE,CAAC,wDAAwD,EAAE,GAAG,EAAE;QAChE,MAAM,GAAG,GAAG,IAAI,eAAe,EAAE,CAAC;QAClC,MAAM,KAAK,GAAG,SAAS,CAAC,EAAE,WAAW,EAAE,aAAa,CAAC,IAAI,EAAE,CAAC,CAAC;QAC7D,MAAM,QAAQ,GAAG,YAAY,EAAE,CAAC;QAChC,MAAM,OAAO,GAAG,IAAI,aAAa,CAC/B,QAAQ,EAAE,KAAK,EAAE,WAAW,EAAE,EAAE,EAAS,EAAE,WAAW,EAAS,EAAE,cAAc,EAAE,EAAE,oBAAoB,EAAS,CACjH,CAAC;QAEF,OAAO,CAAC,sBAAsB,CAAC,GAAG,CAAC,CAAC;QACpC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,oBAAoB,EAAE,EAAE,CAAC,CAAC;QAE7C,MAAM,CAAC,QAAQ,CAAC,qBAAqB,CAAC,iBAAiB,CAAC,IAAW,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACzF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sDAAsD,EAAE,GAAG,EAAE;QAC9D,MAAM,GAAG,GAAG,IAAI,eAAe,EAAE,CAAC;QAClC,MAAM,KAAK,GAAG,SAAS,EAAE,CAAC;QAC1B,MAAM,QAAQ,GAAG,YAAY,EAAE,CAAC;QAChC,MAAM,OAAO,GAAG,IAAI,aAAa,CAC/B,QAAQ,EAAE,KAAK,EAAE,WAAW,EAAE,EAAE,EAAS,EAAE,WAAW,EAAS,EAAE,cAAc,EAAE,EAAE,oBAAoB,EAAS,CACjH,CAAC;QACF,MAAM,eAAe,GAAiC;YACpD,uBAAuB,EAAE,uBAAuB,EAAE,wBAAwB;YAC1E,sBAAsB,EAAE,+BAA+B,EAAE,wBAAwB;SAClF,CAAC;QACF,KAAK,MAAM,GAAG,IAAI,eAAe,EAAE,CAAC;YACjC,QAAQ,CAAC,GAAG,CAAS,CAAC,iBAAiB,CAAC,IAAW,CAAC,CAAC,KAAK,GAAG,IAAI,CAAC;QACrE,CAAC;QAED,OAAO,CAAC,sBAAsB,CAAC,GAAG,CAAC,CAAC;QACpC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,mBAAmB,EAAE,EAAE,CAAC,CAAC;QAE5C,KAAK,MAAM,GAAG,IAAI,eAAe,EAAE,CAAC;YAClC,MAAM,CAAE,QAAQ,CAAC,GAAG,CAAS,CAAC,iBAAiB,CAAC,IAAW,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAClF,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,gFAAgF;AAEhF,QAAQ,CAAC,uCAAuC,EAAE,KAAK,IAAI,EAAE;IAC3D,MAAM,EAAE,aAAa,EAAE,GAAG,MAAM,MAAM,CAAC,+BAA+B,CAAC,CAAC;IAExE,EAAE,CAAC,qFAAqF,EAAE,GAAG,EAAE;QAC7F,MAAM,QAAQ,GAAG,YAAY,EAAE,CAAC;QAChC,MAAM,KAAK,GAAG,SAAS,CAAC,EAAE,WAAW,EAAE,aAAa,CAAC,GAAG,EAAE,CAAC,CAAC;QAC5D,MAAM,OAAO,GAAG,IAAI,aAAa,CAC/B,QAAQ,EAAE,KAAK,EAAE,WAAW,EAAE,EAAE,EAAS,EAAE,WAAW,EAAS,EAAE,cAAc,EAAE,EAAE,oBAAoB,EAAS,CACjH,CAAC;QAEF,MAAM,CAAC,QAAQ,CAAC,oBAAoB,CAAC,iBAAiB,CAAC,IAAW,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAEvF,OAAO,CAAC,kBAAkB,EAAE,CAAC;QAE7B,MAAM,CAAC,QAAQ,CAAC,oBAAoB,CAAC,iBAAiB,CAAC,IAAW,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACtF,MAAM,CAAC,QAAQ,CAAC,qBAAqB,CAAC,iBAAiB,CAAC,IAAW,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACxF,MAAM,CAAC,QAAQ,CAAC,qBAAqB,CAAC,iBAAiB,CAAC,IAAW,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACxF,MAAM,CAAC,QAAQ,CAAC,sBAAsB,CAAC,iBAAiB,CAAC,IAAW,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC3F,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4DAA4D,EAAE,GAAG,EAAE;QACpE,MAAM,QAAQ,GAAG,YAAY,EAAE,CAAC;QAChC,MAAM,KAAK,GAAG,SAAS,CAAC,EAAE,WAAW,EAAE,aAAa,CAAC,IAAI,EAAE,CAAC,CAAC;QAC7D,MAAM,OAAO,GAAG,IAAI,aAAa,CAC/B,QAAQ,EAAE,KAAK,EAAE,WAAW,EAAE,EAAE,EAAS,EAAE,WAAW,EAAS,EAAE,cAAc,EAAE,EAAE,oBAAoB,EAAS,CACjH,CAAC;QAEF,OAAO,CAAC,kBAAkB,EAAE,CAAC;QAE7B,MAAM,CAAC,QAAQ,CAAC,qBAAqB,CAAC,iBAAiB,CAAC,IAAW,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACvF,MAAM,CAAC,QAAQ,CAAC,oBAAoB,CAAC,iBAAiB,CAAC,IAAW,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACzF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4DAA4D,EAAE,GAAG,EAAE;QACpE,MAAM,QAAQ,GAAG,YAAY,EAAE,CAAC;QAChC,MAAM,KAAK,GAAG,SAAS,CAAC,EAAE,WAAW,EAAE,aAAa,CAAC,IAAI,EAAE,CAAC,CAAC;QAC7D,MAAM,OAAO,GAAG,IAAI,aAAa,CAC/B,QAAQ,EAAE,KAAK,EAAE,WAAW,EAAE,EAAE,EAAS,EAAE,WAAW,EAAS,EAAE,cAAc,EAAE,EAAE,oBAAoB,EAAS,CACjH,CAAC;QAEF,OAAO,CAAC,kBAAkB,EAAE,CAAC;QAE7B,MAAM,CAAC,QAAQ,CAAC,qBAAqB,CAAC,iBAAiB,CAAC,IAAW,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACvF,MAAM,CAAC,QAAQ,CAAC,oBAAoB,CAAC,iBAAiB,CAAC,IAAW,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACzF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8DAA8D,EAAE,GAAG,EAAE;QACtE,MAAM,QAAQ,GAAG,YAAY,EAAE,CAAC;QAChC,MAAM,KAAK,GAAG,SAAS,CAAC,EAAE,WAAW,EAAE,aAAa,CAAC,KAAK,EAAE,CAAC,CAAC;QAC9D,MAAM,OAAO,GAAG,IAAI,aAAa,CAC/B,QAAQ,EAAE,KAAK,EAAE,WAAW,EAAE,EAAE,EAAS,EAAE,WAAW,EAAS,EAAE,cAAc,EAAE,EAAE,oBAAoB,EAAS,CACjH,CAAC;QAEF,OAAO,CAAC,kBAAkB,EAAE,CAAC;QAE7B,MAAM,CAAC,QAAQ,CAAC,sBAAsB,CAAC,iBAAiB,CAAC,IAAW,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACxF,MAAM,CAAC,QAAQ,CAAC,oBAAoB,CAAC,iBAAiB,CAAC,IAAW,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACzF,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "homebridge-securitysystem",
3
3
  "displayName": "Homebridge Security System",
4
4
  "type": "module",
5
- "version": "11.3.0",
5
+ "version": "11.3.1-beta.1",
6
6
  "description": "Homebridge plugin that creates a security system accessory that can be triggered by HomeKit sensors.",
7
7
  "author": "MiguelRipoll23",
8
8
  "license": "MIT",
@@ -116,12 +116,20 @@ export class SecuritySystem implements AccessoryPlugin {
116
116
  // Startup tasks.
117
117
  this.logStartup();
118
118
 
119
+ const syncModeSwitches = (): void => {
120
+ this.bus.emit(EventType.RESET_MODE_SWITCHES, {});
121
+ this.bus.emit(EventType.UPDATE_MODE_SWITCHES, {});
122
+ };
123
+
119
124
  if (this.options.saveState) {
120
125
  this.storageService.init().then(() => this.storageService.load(this.state).then(() => {
121
126
  this.svcs.mainService.updateCharacteristic(Char.SecuritySystemTargetState, this.state.targetState);
122
127
  this.svcs.mainService.updateCharacteristic(Char.SecuritySystemCurrentState, this.state.currentState);
123
128
  this.stateHandler.logMode('Current', this.state.currentState);
129
+ syncModeSwitches();
124
130
  }));
131
+ } else {
132
+ syncModeSwitches();
125
133
  }
126
134
 
127
135
  if (this.options.audioPath) {
@@ -0,0 +1,355 @@
1
+ import { describe, it, expect, vi } from 'vitest';
2
+ import { SecurityState } from '../types/security-state-type.js';
3
+ import type { SystemState } from '../interfaces/system-state-interface.js';
4
+ import type { SecuritySystemOptions } from '../interfaces/options-interface.js';
5
+ import type { ServiceRegistry } from '../interfaces/service-registry-interface.js';
6
+
7
+ // ── Minimal mocks ─────────────────────────────────────────────────────────────
8
+
9
+ function makeMockCharacteristic(value: unknown = false) {
10
+ const characteristic = { value, updateValue: vi.fn(), setProps: vi.fn() };
11
+ characteristic.updateValue.mockImplementation((v: unknown) => {
12
+ characteristic.value = v;
13
+ });
14
+ return characteristic;
15
+ }
16
+
17
+ function makeMockService(characteristicValue: unknown = false) {
18
+ const characteristic = makeMockCharacteristic(characteristicValue);
19
+ const service = {
20
+ getCharacteristic: vi.fn().mockReturnValue(characteristic),
21
+ updateCharacteristic: vi.fn((_name: unknown, value: unknown) => {
22
+ characteristic.value = value;
23
+ return service;
24
+ }),
25
+ setCharacteristic: vi.fn().mockReturnThis(),
26
+ addCharacteristic: vi.fn(),
27
+ addOptionalCharacteristic: vi.fn(),
28
+ };
29
+ return service;
30
+ }
31
+
32
+ function makeServices(): ServiceRegistry {
33
+ const keys = [
34
+ 'mainService', 'accessoryInfoService', 'tripSwitchService', 'tripHomeSwitchService',
35
+ 'tripAwaySwitchService', 'tripNightSwitchService', 'tripOverrideSwitchService',
36
+ 'armingLockSwitchService', 'armingLockHomeSwitchService', 'armingLockAwaySwitchService',
37
+ 'armingLockNightSwitchService', 'modeHomeSwitchService', 'modeAwaySwitchService',
38
+ 'modeNightSwitchService', 'modeOffSwitchService', 'modeAwayExtendedSwitchService',
39
+ 'modePauseSwitchService', 'audioSwitchService', 'armingMotionSensorService',
40
+ 'trippedMotionSensorService', 'triggeredMotionSensorService', 'triggeredResetMotionSensorService',
41
+ ];
42
+ const registry: Record<string, ReturnType<typeof makeMockService> | unknown[]> = {};
43
+ for (const key of keys) {
44
+ registry[key] = makeMockService();
45
+ }
46
+ registry.customTripHomeSwitchServices = [];
47
+ registry.customTripAwaySwitchServices = [];
48
+ registry.customTripNightSwitchServices = [];
49
+ return registry as unknown as ServiceRegistry;
50
+ }
51
+
52
+ function makeState(overrides: Partial<SystemState> = {}): SystemState {
53
+ return {
54
+ currentState: SecurityState.OFF,
55
+ targetState: SecurityState.OFF,
56
+ defaultState: SecurityState.OFF,
57
+ availableTargetStates: [SecurityState.HOME, SecurityState.AWAY, SecurityState.NIGHT, SecurityState.OFF],
58
+ isArming: false,
59
+ isTripping: false,
60
+ isKnocked: false,
61
+ serverAuthenticationAttempts: 0,
62
+ pausedCurrentState: null,
63
+ audioProcess: null,
64
+ ...overrides,
65
+ };
66
+ }
67
+
68
+ function makeOptions(overrides: Partial<SecuritySystemOptions> = {}): SecuritySystemOptions {
69
+ return {
70
+ armSeconds: 0,
71
+ triggerSeconds: 0,
72
+ resetMinutes: 10,
73
+ testMode: false,
74
+ proxyMode: false,
75
+ saveState: false,
76
+ overrideOff: false,
77
+ doubleKnock: false,
78
+ doubleKnockSeconds: 90,
79
+ doubleKnockModes: [],
80
+ homeTriggerSeconds: null,
81
+ awayTriggerSeconds: null,
82
+ nightTriggerSeconds: null,
83
+ homeDoubleKnockSeconds: null,
84
+ awayDoubleKnockSeconds: null,
85
+ nightDoubleKnockSeconds: null,
86
+ modeAwayExtendedSwitchTriggerSeconds: null,
87
+ armingLockSwitch: false,
88
+ armingLockSwitches: false,
89
+ disabledModes: [],
90
+ homeArmSeconds: null,
91
+ awayArmSeconds: null,
92
+ nightArmSeconds: null,
93
+ triggeredMotionSensor: false,
94
+ triggeredMotionSensorSeconds: 5,
95
+ trippedMotionSensor: false,
96
+ trippedMotionSensorSeconds: 5,
97
+ resetOffFlow: false,
98
+ ...overrides,
99
+ } as unknown as SecuritySystemOptions;
100
+ }
101
+
102
+ function makeMockLog() {
103
+ return { info: vi.fn(), warn: vi.fn(), error: vi.fn(), debug: vi.fn() };
104
+ }
105
+
106
+ function makeMockStateHandler() {
107
+ return {
108
+ updateTargetState: vi.fn(),
109
+ getArmingSeconds: vi.fn().mockReturnValue(0),
110
+ };
111
+ }
112
+
113
+ function makeMockTimers() {
114
+ return {
115
+ setArmTimer: vi.fn(), clearArmTimer: vi.fn(),
116
+ setTriggerTimer: vi.fn(), clearTriggerTimer: vi.fn(), isTriggerRunning: vi.fn().mockReturnValue(false),
117
+ setPauseTimer: vi.fn(), clearPauseTimer: vi.fn(),
118
+ setDoubleKnockTimer: vi.fn(), clearDoubleKnockTimer: vi.fn(),
119
+ setResetTimer: vi.fn(), clearResetTimer: vi.fn(),
120
+ setTrippedInterval: vi.fn(), clearTrippedInterval: vi.fn(),
121
+ setTriggeredInterval: vi.fn(), clearTriggeredInterval: vi.fn(),
122
+ clearAll: vi.fn(),
123
+ } as any;
124
+ }
125
+
126
+ // ── SwitchHandler tests ───────────────────────────────────────────────────────
127
+
128
+ describe('SwitchHandler.updateModeSwitches', async () => {
129
+ const { SwitchHandler } = await import('../handlers/switch-handler.js');
130
+
131
+ it('sets mode OFF switch ON when targetState is OFF', () => {
132
+ const services = makeServices();
133
+ const state = makeState({ targetState: SecurityState.OFF });
134
+ const handler = new SwitchHandler(
135
+ services, state, makeOptions(), {} as any, makeMockLog() as any, makeMockTimers(), makeMockStateHandler() as any,
136
+ );
137
+ const offCharacteristic = services.modeOffSwitchService.getCharacteristic('On' as any)!;
138
+
139
+ handler.updateModeSwitches();
140
+
141
+ expect(offCharacteristic.value).toBe(true);
142
+ });
143
+
144
+ it('sets mode HOME switch ON when targetState is HOME', () => {
145
+ const services = makeServices();
146
+ const state = makeState({ targetState: SecurityState.HOME });
147
+ const handler = new SwitchHandler(
148
+ services, state, makeOptions(), {} as any, makeMockLog() as any, makeMockTimers(), makeMockStateHandler() as any,
149
+ );
150
+
151
+ handler.updateModeSwitches();
152
+
153
+ expect(services.modeHomeSwitchService.getCharacteristic('On' as any).value).toBe(true);
154
+ });
155
+
156
+ it('sets mode AWAY switch ON when targetState is AWAY', () => {
157
+ const services = makeServices();
158
+ const state = makeState({ targetState: SecurityState.AWAY });
159
+ const handler = new SwitchHandler(
160
+ services, state, makeOptions(), {} as any, makeMockLog() as any, makeMockTimers(), makeMockStateHandler() as any,
161
+ );
162
+
163
+ handler.updateModeSwitches();
164
+
165
+ expect(services.modeAwaySwitchService.getCharacteristic('On' as any).value).toBe(true);
166
+ });
167
+
168
+ it('sets mode NIGHT switch ON when targetState is NIGHT', () => {
169
+ const services = makeServices();
170
+ const state = makeState({ targetState: SecurityState.NIGHT });
171
+ const handler = new SwitchHandler(
172
+ services, state, makeOptions(), {} as any, makeMockLog() as any, makeMockTimers(), makeMockStateHandler() as any,
173
+ );
174
+
175
+ handler.updateModeSwitches();
176
+
177
+ expect(services.modeNightSwitchService.getCharacteristic('On' as any).value).toBe(true);
178
+ });
179
+
180
+ it('does not turn on any mode switch when targetState is TRIGGERED', () => {
181
+ const services = makeServices();
182
+ const state = makeState({ targetState: SecurityState.TRIGGERED });
183
+ const handler = new SwitchHandler(
184
+ services, state, makeOptions(), {} as any, makeMockLog() as any, makeMockTimers(), makeMockStateHandler() as any,
185
+ );
186
+ const modeServices = [
187
+ services.modeHomeSwitchService, services.modeAwaySwitchService,
188
+ services.modeNightSwitchService, services.modeOffSwitchService,
189
+ services.modeAwayExtendedSwitchService, services.modePauseSwitchService,
190
+ ];
191
+
192
+ handler.updateModeSwitches();
193
+
194
+ for (const service of modeServices) {
195
+ expect(service.updateCharacteristic).not.toHaveBeenCalled();
196
+ }
197
+ });
198
+
199
+ it('updates characteristic via updateCharacteristic (HomeKit compliant)', () => {
200
+ const services = makeServices();
201
+ const state = makeState({ targetState: SecurityState.OFF });
202
+ const Characteristic = { On: 'On' };
203
+ const handler = new SwitchHandler(
204
+ services, state, makeOptions(), Characteristic as any, makeMockLog() as any, makeMockTimers(), makeMockStateHandler() as any,
205
+ );
206
+
207
+ handler.updateModeSwitches();
208
+
209
+ expect(services.modeOffSwitchService.updateCharacteristic).toHaveBeenCalledWith('On', true);
210
+ });
211
+ });
212
+
213
+ describe('SwitchHandler.resetModeSwitches', async () => {
214
+ const { SwitchHandler } = await import('../handlers/switch-handler.js');
215
+
216
+ it('turns OFF all mode switches that are ON', () => {
217
+ const services = makeServices();
218
+ const state = makeState();
219
+ const handler = new SwitchHandler(
220
+ services, state, makeOptions(), {} as any, makeMockLog() as any, makeMockTimers(), makeMockStateHandler() as any,
221
+ );
222
+ const modeServiceKeys: Array<keyof ServiceRegistry> = [
223
+ 'modeHomeSwitchService', 'modeAwaySwitchService', 'modeNightSwitchService',
224
+ 'modeOffSwitchService', 'modeAwayExtendedSwitchService', 'modePauseSwitchService',
225
+ ];
226
+ for (const key of modeServiceKeys) {
227
+ (services[key] as any).getCharacteristic('On' as any).value = true;
228
+ }
229
+
230
+ handler.resetModeSwitches();
231
+
232
+ for (const key of modeServiceKeys) {
233
+ expect((services[key] as any).getCharacteristic('On' as any).value).toBe(false);
234
+ }
235
+ });
236
+
237
+ it('does not call updateValue on switches that are already OFF', () => {
238
+ const services = makeServices();
239
+ const state = makeState();
240
+ const handler = new SwitchHandler(
241
+ services, state, makeOptions(), {} as any, makeMockLog() as any, makeMockTimers(), makeMockStateHandler() as any,
242
+ );
243
+ const offCharacteristic = services.modeOffSwitchService.getCharacteristic('On' as any)!;
244
+ offCharacteristic.value = false;
245
+
246
+ handler.resetModeSwitches();
247
+
248
+ expect(offCharacteristic.updateValue).not.toHaveBeenCalled();
249
+ });
250
+ });
251
+
252
+ describe('SwitchHandler.subscribeToStateEvents', async () => {
253
+ const { SwitchHandler } = await import('../handlers/switch-handler.js');
254
+ const { EventBusService } = await import('../services/event-bus-service.js');
255
+ const { EventType } = await import('../types/event-type.js');
256
+
257
+ it('calls updateModeSwitches on UPDATE_MODE_SWITCHES event', () => {
258
+ const bus = new EventBusService();
259
+ const state = makeState({ targetState: SecurityState.HOME });
260
+ const services = makeServices();
261
+ const handler = new SwitchHandler(
262
+ services, state, makeOptions(), {} as any, makeMockLog() as any, makeMockTimers(), makeMockStateHandler() as any,
263
+ );
264
+
265
+ handler.subscribeToStateEvents(bus);
266
+ bus.emit(EventType.UPDATE_MODE_SWITCHES, {});
267
+
268
+ expect(services.modeHomeSwitchService.getCharacteristic('On' as any).value).toBe(true);
269
+ });
270
+
271
+ it('calls resetModeSwitches on RESET_MODE_SWITCHES event', () => {
272
+ const bus = new EventBusService();
273
+ const state = makeState();
274
+ const services = makeServices();
275
+ const handler = new SwitchHandler(
276
+ services, state, makeOptions(), {} as any, makeMockLog() as any, makeMockTimers(), makeMockStateHandler() as any,
277
+ );
278
+ const modeServiceKeys: Array<keyof ServiceRegistry> = [
279
+ 'modeHomeSwitchService', 'modeAwaySwitchService', 'modeNightSwitchService',
280
+ 'modeOffSwitchService', 'modeAwayExtendedSwitchService', 'modePauseSwitchService',
281
+ ];
282
+ for (const key of modeServiceKeys) {
283
+ (services[key] as any).getCharacteristic('On' as any).value = true;
284
+ }
285
+
286
+ handler.subscribeToStateEvents(bus);
287
+ bus.emit(EventType.RESET_MODE_SWITCHES, {});
288
+
289
+ for (const key of modeServiceKeys) {
290
+ expect((services[key] as any).getCharacteristic('On' as any).value).toBe(false);
291
+ }
292
+ });
293
+ });
294
+
295
+ // ── Regression: mode switch sync on startup ──────────────────────────────────
296
+
297
+ describe('SwitchHandler startup sync regression', async () => {
298
+ const { SwitchHandler } = await import('../handlers/switch-handler.js');
299
+
300
+ it('sets mode OFF switch ON when state is initialized to OFF (regression test for #889)', () => {
301
+ const services = makeServices();
302
+ const state = makeState({ targetState: SecurityState.OFF });
303
+ const handler = new SwitchHandler(
304
+ services, state, makeOptions(), {} as any, makeMockLog() as any, makeMockTimers(), makeMockStateHandler() as any,
305
+ );
306
+
307
+ expect(services.modeOffSwitchService.getCharacteristic('On' as any).value).toBe(false);
308
+
309
+ handler.updateModeSwitches();
310
+
311
+ expect(services.modeOffSwitchService.getCharacteristic('On' as any).value).toBe(true);
312
+ expect(services.modeHomeSwitchService.getCharacteristic('On' as any).value).toBe(false);
313
+ expect(services.modeAwaySwitchService.getCharacteristic('On' as any).value).toBe(false);
314
+ expect(services.modeNightSwitchService.getCharacteristic('On' as any).value).toBe(false);
315
+ });
316
+
317
+ it('sets mode HOME switch ON when state is initialized to HOME', () => {
318
+ const services = makeServices();
319
+ const state = makeState({ targetState: SecurityState.HOME });
320
+ const handler = new SwitchHandler(
321
+ services, state, makeOptions(), {} as any, makeMockLog() as any, makeMockTimers(), makeMockStateHandler() as any,
322
+ );
323
+
324
+ handler.updateModeSwitches();
325
+
326
+ expect(services.modeHomeSwitchService.getCharacteristic('On' as any).value).toBe(true);
327
+ expect(services.modeOffSwitchService.getCharacteristic('On' as any).value).toBe(false);
328
+ });
329
+
330
+ it('sets mode AWAY switch ON when state is initialized to AWAY', () => {
331
+ const services = makeServices();
332
+ const state = makeState({ targetState: SecurityState.AWAY });
333
+ const handler = new SwitchHandler(
334
+ services, state, makeOptions(), {} as any, makeMockLog() as any, makeMockTimers(), makeMockStateHandler() as any,
335
+ );
336
+
337
+ handler.updateModeSwitches();
338
+
339
+ expect(services.modeAwaySwitchService.getCharacteristic('On' as any).value).toBe(true);
340
+ expect(services.modeOffSwitchService.getCharacteristic('On' as any).value).toBe(false);
341
+ });
342
+
343
+ it('sets mode NIGHT switch ON when state is initialized to NIGHT', () => {
344
+ const services = makeServices();
345
+ const state = makeState({ targetState: SecurityState.NIGHT });
346
+ const handler = new SwitchHandler(
347
+ services, state, makeOptions(), {} as any, makeMockLog() as any, makeMockTimers(), makeMockStateHandler() as any,
348
+ );
349
+
350
+ handler.updateModeSwitches();
351
+
352
+ expect(services.modeNightSwitchService.getCharacteristic('On' as any).value).toBe(true);
353
+ expect(services.modeOffSwitchService.getCharacteristic('On' as any).value).toBe(false);
354
+ });
355
+ });