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.
- package/.github/workflows/publish.yml +3 -0
- package/AGENTS.md +214 -0
- package/dist/conditions/already-triggered-condition.d.ts +10 -0
- package/dist/conditions/already-triggered-condition.js +16 -0
- package/dist/conditions/already-triggered-condition.js.map +1 -0
- package/dist/conditions/arming-in-progress-condition.d.ts +10 -0
- package/dist/conditions/arming-in-progress-condition.js +15 -0
- package/dist/conditions/arming-in-progress-condition.js.map +1 -0
- package/dist/conditions/arming-lock-condition.d.ts +13 -0
- package/dist/conditions/arming-lock-condition.js +42 -0
- package/dist/conditions/arming-lock-condition.js.map +1 -0
- package/dist/conditions/condition.d.ts +15 -0
- package/dist/conditions/condition.js +9 -0
- package/dist/conditions/condition.js.map +1 -0
- package/dist/conditions/double-knock-condition.d.ts +22 -0
- package/dist/conditions/double-knock-condition.js +70 -0
- package/dist/conditions/double-knock-condition.js.map +1 -0
- package/dist/conditions/not-armed-condition.d.ts +10 -0
- package/dist/conditions/not-armed-condition.js +20 -0
- package/dist/conditions/not-armed-condition.js.map +1 -0
- package/dist/constants/default-constant.d.ts +26 -0
- package/dist/constants/default-constant.js +28 -0
- package/dist/constants/default-constant.js.map +1 -0
- package/dist/constants/homekit-constant.d.ts +4 -0
- package/dist/constants/homekit-constant.js +5 -0
- package/dist/constants/homekit-constant.js.map +1 -0
- package/dist/constants/switch-uuid-constant.d.ts +23 -0
- package/dist/constants/switch-uuid-constant.js +24 -0
- package/dist/constants/switch-uuid-constant.js.map +1 -0
- package/dist/handlers/sensor-handler.d.ts +17 -0
- package/dist/handlers/sensor-handler.js +53 -0
- package/dist/handlers/sensor-handler.js.map +1 -0
- package/dist/handlers/state-handler.d.ts +41 -0
- package/dist/handlers/state-handler.js +213 -0
- package/dist/handlers/state-handler.js.map +1 -0
- package/dist/handlers/switch-handler.d.ts +27 -0
- package/dist/handlers/switch-handler.js +139 -0
- package/dist/handlers/switch-handler.js.map +1 -0
- package/dist/handlers/trip-handler.d.ts +45 -0
- package/dist/handlers/trip-handler.js +179 -0
- package/dist/handlers/trip-handler.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -0
- package/dist/interfaces/condition-context-interface.d.ts +13 -0
- package/dist/interfaces/condition-context-interface.js +2 -0
- package/dist/interfaces/condition-context-interface.js.map +1 -0
- package/dist/interfaces/hap-types-interface.d.ts +9 -0
- package/dist/interfaces/hap-types-interface.js +2 -0
- package/dist/interfaces/hap-types-interface.js.map +1 -0
- package/dist/interfaces/options-interface.d.ts +93 -0
- package/dist/interfaces/options-interface.js +2 -0
- package/dist/interfaces/options-interface.js.map +1 -0
- package/dist/interfaces/persisted-state-interface.d.ts +6 -0
- package/dist/interfaces/persisted-state-interface.js +2 -0
- package/dist/interfaces/persisted-state-interface.js.map +1 -0
- package/dist/interfaces/service-registry-interface.d.ts +26 -0
- package/dist/interfaces/service-registry-interface.js +2 -0
- package/dist/interfaces/service-registry-interface.js.map +1 -0
- package/dist/interfaces/system-state-interface.d.ts +21 -0
- package/dist/interfaces/system-state-interface.js +2 -0
- package/dist/interfaces/system-state-interface.js.map +1 -0
- package/dist/security-system.d.ts +26 -0
- package/dist/security-system.js +377 -0
- package/dist/security-system.js.map +1 -0
- package/dist/services/audio-service.d.ts +21 -0
- package/dist/services/audio-service.js +113 -0
- package/dist/services/audio-service.js.map +1 -0
- package/dist/services/command-service.d.ts +16 -0
- package/dist/services/command-service.js +65 -0
- package/dist/services/command-service.js.map +1 -0
- package/dist/services/event-bus-service.d.ts +12 -0
- package/dist/services/event-bus-service.js +17 -0
- package/dist/services/event-bus-service.js.map +1 -0
- package/dist/services/server-service.d.ts +25 -0
- package/dist/services/server-service.js +140 -0
- package/dist/services/server-service.js.map +1 -0
- package/dist/services/storage-service.d.ts +14 -0
- package/dist/services/storage-service.js +70 -0
- package/dist/services/storage-service.js.map +1 -0
- package/dist/services/webhook-service.d.ts +16 -0
- package/dist/services/webhook-service.js +73 -0
- package/dist/services/webhook-service.js.map +1 -0
- package/dist/tests/conditions.test.d.ts +1 -0
- package/dist/tests/conditions.test.js +151 -0
- package/dist/tests/conditions.test.js.map +1 -0
- package/dist/tests/state-handler.test.d.ts +1 -0
- package/dist/tests/state-handler.test.js +171 -0
- package/dist/tests/state-handler.test.js.map +1 -0
- package/dist/tests/trip-handler.test.d.ts +1 -0
- package/dist/tests/trip-handler.test.js +160 -0
- package/dist/tests/trip-handler.test.js.map +1 -0
- package/dist/types/event-payload-map-type.d.ts +9 -0
- package/dist/types/event-payload-map-type.js +2 -0
- package/dist/types/event-payload-map-type.js.map +1 -0
- package/dist/types/event-type.d.ts +24 -0
- package/dist/types/event-type.js +9 -0
- package/dist/types/event-type.js.map +1 -0
- package/dist/types/mode-type.d.ts +4 -0
- package/dist/types/mode-type.js +2 -0
- package/dist/types/mode-type.js.map +1 -0
- package/dist/types/origin-type.d.ts +9 -0
- package/dist/types/origin-type.js +11 -0
- package/dist/types/origin-type.js.map +1 -0
- package/dist/types/security-state-type.d.ts +11 -0
- package/dist/types/security-state-type.js +13 -0
- package/dist/types/security-state-type.js.map +1 -0
- package/dist/utils/log-util.d.ts +4 -0
- package/dist/utils/log-util.js +47 -0
- package/dist/utils/log-util.js.map +1 -0
- package/dist/utils/options-util.d.ts +6 -0
- package/dist/utils/options-util.js +171 -0
- package/dist/utils/options-util.js.map +1 -0
- package/dist/utils/state-util.d.ts +8 -0
- package/dist/utils/state-util.js +29 -0
- package/dist/utils/state-util.js.map +1 -0
- package/eslint.config.js +35 -0
- package/package.json +40 -34
- package/src/@types/homebridge-lib.d.ts +14 -0
- package/src/conditions/already-triggered-condition.ts +18 -0
- package/src/conditions/arming-in-progress-condition.ts +17 -0
- package/src/conditions/arming-lock-condition.ts +48 -0
- package/src/conditions/condition.ts +17 -0
- package/src/conditions/double-knock-condition.ts +82 -0
- package/src/conditions/not-armed-condition.ts +24 -0
- package/src/constants/default-constant.ts +28 -0
- package/src/constants/homekit-constant.ts +5 -0
- package/src/constants/switch-uuid-constant.ts +23 -0
- package/src/handlers/sensor-handler.ts +81 -0
- package/src/handlers/state-handler.ts +268 -0
- package/src/handlers/switch-handler.ts +166 -0
- package/src/handlers/trip-handler.ts +219 -0
- package/src/index.ts +9 -0
- package/src/interfaces/condition-context-interface.ts +14 -0
- package/src/interfaces/hap-types-interface.ts +11 -0
- package/src/interfaces/options-interface.ts +120 -0
- package/src/interfaces/persisted-state-interface.ts +7 -0
- package/src/interfaces/service-registry-interface.ts +37 -0
- package/src/interfaces/system-state-interface.ts +25 -0
- package/src/security-system.ts +433 -0
- package/src/services/audio-service.ts +133 -0
- package/src/services/command-service.ts +76 -0
- package/src/services/event-bus-service.ts +21 -0
- package/src/services/server-service.ts +176 -0
- package/src/services/storage-service.ts +80 -0
- package/src/services/webhook-service.ts +83 -0
- package/src/tests/conditions.test.ts +180 -0
- package/src/tests/state-handler.test.ts +200 -0
- package/src/tests/trip-handler.test.ts +182 -0
- package/src/types/event-payload-map-type.ts +15 -0
- package/src/types/event-type.ts +29 -0
- package/src/types/mode-type.ts +4 -0
- package/src/types/origin-type.ts +9 -0
- package/src/types/security-state-type.ts +11 -0
- package/src/utils/log-util.ts +54 -0
- package/src/utils/options-util.ts +202 -0
- package/src/utils/state-util.ts +32 -0
- package/tsconfig.json +25 -0
- package/vitest.config.ts +8 -0
- package/.eslintrc.js +0 -16
- package/.vscode/settings.json +0 -12
- package/src/index.js +0 -2525
- package/src/utils/options.js +0 -409
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
import type { Logging } from 'homebridge';
|
|
2
|
+
import type { CharacteristicConstructor } from '../interfaces/hap-types-interface.js';
|
|
3
|
+
import { SecurityState } from '../types/security-state-type.js';
|
|
4
|
+
import { OriginType } from '../types/origin-type.js';
|
|
5
|
+
import { HK_NOT_ALLOWED_IN_CURRENT_STATE } from '../constants/homekit-constant.js';
|
|
6
|
+
import type { ServiceRegistry } from '../interfaces/service-registry-interface.js';
|
|
7
|
+
import type { SystemState } from '../interfaces/system-state-interface.js';
|
|
8
|
+
import type { SecuritySystemOptions } from '../interfaces/options-interface.js';
|
|
9
|
+
import type { EventBusService } from '../services/event-bus-service.js';
|
|
10
|
+
import { EventType } from '../types/event-type.js';
|
|
11
|
+
import type { AudioService } from '../services/audio-service.js';
|
|
12
|
+
import type { SensorHandler } from './sensor-handler.js';
|
|
13
|
+
import type { StateHandler } from './state-handler.js';
|
|
14
|
+
import { NotArmedCondition } from '../conditions/not-armed-condition.js';
|
|
15
|
+
import { ArmingInProgressCondition } from '../conditions/arming-in-progress-condition.js';
|
|
16
|
+
import { AlreadyTriggeredCondition } from '../conditions/already-triggered-condition.js';
|
|
17
|
+
import { DoubleKnockCondition } from '../conditions/double-knock-condition.js';
|
|
18
|
+
import type { ConditionContext } from '../interfaces/condition-context-interface.js';
|
|
19
|
+
|
|
20
|
+
/** Handles the trip switch and trigger-delay logic, including all blocking conditions. */
|
|
21
|
+
export class TripHandler {
|
|
22
|
+
private stateHandler!: StateHandler;
|
|
23
|
+
|
|
24
|
+
private readonly notArmed = new NotArmedCondition();
|
|
25
|
+
private readonly armingInProgress = new ArmingInProgressCondition();
|
|
26
|
+
private readonly alreadyTriggered = new AlreadyTriggeredCondition();
|
|
27
|
+
private readonly doubleKnock: DoubleKnockCondition;
|
|
28
|
+
|
|
29
|
+
constructor(
|
|
30
|
+
private readonly services: ServiceRegistry,
|
|
31
|
+
private readonly state: SystemState,
|
|
32
|
+
private readonly options: SecuritySystemOptions,
|
|
33
|
+
private readonly Characteristic: CharacteristicConstructor,
|
|
34
|
+
private readonly log: Logging,
|
|
35
|
+
private readonly bus: EventBusService,
|
|
36
|
+
private readonly audio: AudioService,
|
|
37
|
+
private readonly sensorHandler: SensorHandler,
|
|
38
|
+
) {
|
|
39
|
+
this.doubleKnock = new DoubleKnockCondition((seconds, onExpire) => {
|
|
40
|
+
this.log.warn('Trip Switch (Knock)');
|
|
41
|
+
this.state.doubleKnockTimeout = setTimeout(() => {
|
|
42
|
+
onExpire();
|
|
43
|
+
this.log.info('Trip Switch (Reset)');
|
|
44
|
+
}, seconds * 1000);
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
setStateHandler(handler: StateHandler): void {
|
|
49
|
+
this.stateHandler = handler;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Core trip-switch logic shared by all trip/trigger paths.
|
|
54
|
+
* Returns `true` on success, `false` if blocked.
|
|
55
|
+
*/
|
|
56
|
+
updateTripSwitch(value: boolean, origin: OriginType, stateChanged: boolean): boolean {
|
|
57
|
+
const ctx: ConditionContext = {
|
|
58
|
+
state: this.state,
|
|
59
|
+
services: this.services,
|
|
60
|
+
options: this.options,
|
|
61
|
+
value,
|
|
62
|
+
origin,
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
if (value) {
|
|
66
|
+
// Check blocking conditions in order.
|
|
67
|
+
if (this.notArmed.evaluate(ctx)) {
|
|
68
|
+
this.log.warn('Trip Switch (Not armed)');
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (this.armingInProgress.evaluate(ctx)) {
|
|
73
|
+
this.log.warn('Trip Switch (Still arming)');
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (this.doubleKnock.evaluate(ctx)) {
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Clear any lingering double-knock timeout once we've passed it.
|
|
82
|
+
if (this.state.doubleKnockTimeout !== null) {
|
|
83
|
+
clearTimeout(this.state.doubleKnockTimeout);
|
|
84
|
+
this.state.doubleKnockTimeout = null;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (this.alreadyTriggered.evaluate(ctx)) {
|
|
88
|
+
this.log.warn('Security System (Already triggered)');
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (this.state.triggerTimeout !== null) {
|
|
93
|
+
this.log.warn('Security System (Already tripped)');
|
|
94
|
+
return false;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
this.activateTrip(origin);
|
|
98
|
+
} else {
|
|
99
|
+
this.cancelTrip(origin, stateChanged);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Sync trip switch characteristic when origin is not a direct switch press.
|
|
103
|
+
if (origin === OriginType.INTERNAL || origin === OriginType.EXTERNAL) {
|
|
104
|
+
this.services.tripSwitchService.updateCharacteristic(this.Characteristic.On, value);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return true;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Trip a mode-specific switch. Only triggers if the system is currently in
|
|
112
|
+
* the required mode (or the alarm is triggered and target matches).
|
|
113
|
+
*/
|
|
114
|
+
triggerIfModeSet(requiredState: SecurityState, value: boolean): boolean {
|
|
115
|
+
const isTriggered = this.state.currentState === SecurityState.TRIGGERED;
|
|
116
|
+
|
|
117
|
+
if (value) {
|
|
118
|
+
const modeMatches = this.state.currentState === requiredState
|
|
119
|
+
|| (isTriggered && this.state.targetState === requiredState);
|
|
120
|
+
|
|
121
|
+
if (!modeMatches) {
|
|
122
|
+
this.log.debug('Security System (Trip mode not set)');
|
|
123
|
+
return false;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return this.updateTripSwitch(value, OriginType.REGULAR_SWITCH, false);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
resetTripSwitches(): void {
|
|
131
|
+
const switches: Array<[keyof ServiceRegistry, string]> = [
|
|
132
|
+
['tripHomeSwitchService', 'Trip Home'],
|
|
133
|
+
['tripAwaySwitchService', 'Trip Away'],
|
|
134
|
+
['tripNightSwitchService', 'Trip Night'],
|
|
135
|
+
['tripOverrideSwitchService', 'Trip Override'],
|
|
136
|
+
];
|
|
137
|
+
|
|
138
|
+
for (const [key, label] of switches) {
|
|
139
|
+
const char = this.services[key].getCharacteristic(this.Characteristic.On);
|
|
140
|
+
if (char.value) {
|
|
141
|
+
char.updateValue(false);
|
|
142
|
+
this.log.debug(`${label} Switch (Off)`);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
private activateTrip(origin: OriginType): void {
|
|
148
|
+
this.log.info('Security System (Tripped)');
|
|
149
|
+
|
|
150
|
+
if (this.options.trippedMotionSensor) {
|
|
151
|
+
this.sensorHandler.pulseTrippedMotionSensor();
|
|
152
|
+
this.state.trippedMotionSensorInterval = setInterval(
|
|
153
|
+
() => this.sensorHandler.pulseTrippedMotionSensor(),
|
|
154
|
+
this.options.trippedMotionSensorSeconds * 1000,
|
|
155
|
+
);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const triggerSeconds = this.resolveTriggerSeconds();
|
|
159
|
+
this.log.debug(`Trigger delay (${triggerSeconds}s)`);
|
|
160
|
+
|
|
161
|
+
this.state.triggerTimeout = setTimeout(() => {
|
|
162
|
+
this.state.triggerTimeout = null;
|
|
163
|
+
this.stateHandler.setCurrentState(SecurityState.TRIGGERED, origin);
|
|
164
|
+
}, triggerSeconds * 1000);
|
|
165
|
+
|
|
166
|
+
if (triggerSeconds > 0) {
|
|
167
|
+
this.bus.emit(EventType.WARNING, { origin, triggerSeconds });
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
private cancelTrip(origin: OriginType, stateChanged: boolean): void {
|
|
172
|
+
this.log.info('Security System (Cancelled)');
|
|
173
|
+
this.audio.stop();
|
|
174
|
+
|
|
175
|
+
if (this.state.currentState === SecurityState.TRIGGERED) {
|
|
176
|
+
if (!stateChanged) {
|
|
177
|
+
this.stateHandler.updateTargetState(SecurityState.OFF, OriginType.INTERNAL, 0);
|
|
178
|
+
}
|
|
179
|
+
} else {
|
|
180
|
+
this.stateHandler.resetTimers();
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
if (this.options.trippedMotionSensor) {
|
|
184
|
+
this.sensorHandler.resetTrippedMotionSensor();
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
this.state.isKnocked = false;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
private resolveTriggerSeconds(): number {
|
|
191
|
+
const seconds = this.options.triggerSeconds;
|
|
192
|
+
const cur = this.state.currentState;
|
|
193
|
+
|
|
194
|
+
if (cur === SecurityState.HOME && this.options.homeTriggerSeconds !== null) {
|
|
195
|
+
return this.options.homeTriggerSeconds;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
if (cur === SecurityState.AWAY) {
|
|
199
|
+
const extChar = this.services.modeAwayExtendedSwitchService
|
|
200
|
+
.getCharacteristic(this.Characteristic.On);
|
|
201
|
+
|
|
202
|
+
if (this.options.modeAwayExtendedSwitchTriggerSeconds !== null && extChar.value) {
|
|
203
|
+
return this.options.modeAwayExtendedSwitchTriggerSeconds;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
if (this.options.awayTriggerSeconds !== null) {
|
|
207
|
+
return this.options.awayTriggerSeconds;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
if (cur === SecurityState.NIGHT && this.options.nightTriggerSeconds !== null) {
|
|
212
|
+
return this.options.nightTriggerSeconds;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
return seconds;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
export { HK_NOT_ALLOWED_IN_CURRENT_STATE };
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { API } from 'homebridge';
|
|
2
|
+
import { SecuritySystem } from './security-system.js';
|
|
3
|
+
|
|
4
|
+
const PLUGIN_NAME = 'homebridge-securitysystem';
|
|
5
|
+
const ACCESSORY_NAME = 'security-system';
|
|
6
|
+
|
|
7
|
+
export default (api: API): void => {
|
|
8
|
+
api.registerAccessory(PLUGIN_NAME, ACCESSORY_NAME, SecuritySystem);
|
|
9
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { OriginType } from '../types/origin-type.js';
|
|
2
|
+
import type { SecuritySystemOptions } from './options-interface.js';
|
|
3
|
+
import type { ServiceRegistry } from './service-registry-interface.js';
|
|
4
|
+
import type { SystemState } from './system-state-interface.js';
|
|
5
|
+
|
|
6
|
+
/** Context passed to Condition.evaluate() to determine if an action is blocked. */
|
|
7
|
+
export interface ConditionContext {
|
|
8
|
+
state: SystemState;
|
|
9
|
+
services: ServiceRegistry;
|
|
10
|
+
options: SecuritySystemOptions;
|
|
11
|
+
/** The value being set (true = activating, false = deactivating). */
|
|
12
|
+
value: boolean;
|
|
13
|
+
origin: OriginType;
|
|
14
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { API } from 'homebridge';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Runtime type of `api.hap.Characteristic` (the class with all static characteristic
|
|
5
|
+
* definitions). Using `API['hap']['Characteristic']` avoids the self-referential
|
|
6
|
+
* `typeof Characteristic` issue that arises with `import type { Characteristic }`.
|
|
7
|
+
*/
|
|
8
|
+
export type CharacteristicConstructor = API['hap']['Characteristic'];
|
|
9
|
+
|
|
10
|
+
/** Runtime type of `api.hap.Service`. */
|
|
11
|
+
export type ServiceConstructor = API['hap']['Service'];
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/** Key-value pair for extra ffplay environment variables. */
|
|
2
|
+
export interface AudioVariable {
|
|
3
|
+
key: string;
|
|
4
|
+
value: string;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
/** Fully-parsed, strongly-typed configuration options for the security system. */
|
|
8
|
+
export interface SecuritySystemOptions {
|
|
9
|
+
name: string;
|
|
10
|
+
serialNumber: string;
|
|
11
|
+
defaultMode: string;
|
|
12
|
+
armSeconds: number;
|
|
13
|
+
triggerSeconds: number;
|
|
14
|
+
resetMinutes: number;
|
|
15
|
+
saveState: boolean;
|
|
16
|
+
proxyMode: boolean;
|
|
17
|
+
testMode: boolean;
|
|
18
|
+
|
|
19
|
+
// Switch display names
|
|
20
|
+
tripSwitchName: string;
|
|
21
|
+
tripHomeSwitchName: string;
|
|
22
|
+
tripAwaySwitchName: string;
|
|
23
|
+
tripNightSwitchName: string;
|
|
24
|
+
tripOverrideSwitchName: string;
|
|
25
|
+
modeHomeSwitchName: string;
|
|
26
|
+
modeAwaySwitchName: string;
|
|
27
|
+
modeNightSwitchName: string;
|
|
28
|
+
modeOffSwitchName: string;
|
|
29
|
+
modeAwayExtendedSwitchName: string;
|
|
30
|
+
modePauseSwitchName: string;
|
|
31
|
+
audioSwitchName: string;
|
|
32
|
+
|
|
33
|
+
// Behaviour toggles
|
|
34
|
+
logDirectory: string | null;
|
|
35
|
+
overrideOff: boolean;
|
|
36
|
+
resetOffFlow: boolean;
|
|
37
|
+
disabledModes: string[];
|
|
38
|
+
|
|
39
|
+
// Per-mode arm delays (null = use global armSeconds)
|
|
40
|
+
homeArmSeconds: number | null;
|
|
41
|
+
awayArmSeconds: number | null;
|
|
42
|
+
nightArmSeconds: number | null;
|
|
43
|
+
|
|
44
|
+
// Per-mode trigger delays (null = use global triggerSeconds)
|
|
45
|
+
homeTriggerSeconds: number | null;
|
|
46
|
+
awayTriggerSeconds: number | null;
|
|
47
|
+
nightTriggerSeconds: number | null;
|
|
48
|
+
|
|
49
|
+
// Trip switches
|
|
50
|
+
tripSwitch: boolean;
|
|
51
|
+
tripOverrideSwitch: boolean;
|
|
52
|
+
tripModeSwitches: boolean;
|
|
53
|
+
|
|
54
|
+
// Arming lock
|
|
55
|
+
armingLockSwitch: boolean;
|
|
56
|
+
armingLockSwitches: boolean;
|
|
57
|
+
|
|
58
|
+
// Motion sensors
|
|
59
|
+
armingMotionSensor: boolean;
|
|
60
|
+
trippedMotionSensor: boolean;
|
|
61
|
+
trippedMotionSensorSeconds: number;
|
|
62
|
+
triggeredMotionSensor: boolean;
|
|
63
|
+
triggeredMotionSensorSeconds: number;
|
|
64
|
+
resetSensor: boolean;
|
|
65
|
+
|
|
66
|
+
// Mode switches
|
|
67
|
+
modeSwitches: boolean;
|
|
68
|
+
modeOffSwitch: boolean;
|
|
69
|
+
modePauseSwitch: boolean;
|
|
70
|
+
pauseMinutes: number;
|
|
71
|
+
modeAwayExtendedSwitch: boolean;
|
|
72
|
+
modeAwayExtendedSwitchTriggerSeconds: number | null;
|
|
73
|
+
|
|
74
|
+
// Double-knock
|
|
75
|
+
doubleKnock: boolean;
|
|
76
|
+
doubleKnockSeconds: number;
|
|
77
|
+
doubleKnockModes: string[];
|
|
78
|
+
homeDoubleKnockSeconds: number | null;
|
|
79
|
+
awayDoubleKnockSeconds: number | null;
|
|
80
|
+
nightDoubleKnockSeconds: number | null;
|
|
81
|
+
|
|
82
|
+
// Audio
|
|
83
|
+
audio: boolean;
|
|
84
|
+
audioPath: string | null;
|
|
85
|
+
audioLanguage: string;
|
|
86
|
+
audioVolume: number | null;
|
|
87
|
+
audioArmingLooped: boolean;
|
|
88
|
+
audioAlertLooped: boolean;
|
|
89
|
+
audioExtraVariables: AudioVariable[];
|
|
90
|
+
audioSwitch: boolean;
|
|
91
|
+
|
|
92
|
+
// Server
|
|
93
|
+
serverPort: number | null;
|
|
94
|
+
serverCode: number | null;
|
|
95
|
+
|
|
96
|
+
// Shell commands
|
|
97
|
+
commandTargetHome: string | null;
|
|
98
|
+
commandTargetAway: string | null;
|
|
99
|
+
commandTargetNight: string | null;
|
|
100
|
+
commandTargetOff: string | null;
|
|
101
|
+
commandCurrentHome: string | null;
|
|
102
|
+
commandCurrentAway: string | null;
|
|
103
|
+
commandCurrentNight: string | null;
|
|
104
|
+
commandCurrentOff: string | null;
|
|
105
|
+
commandCurrentWarning: string | null;
|
|
106
|
+
commandCurrentTriggered: string | null;
|
|
107
|
+
|
|
108
|
+
// Webhooks
|
|
109
|
+
webhookUrl: string | null;
|
|
110
|
+
webhookTargetHome: string | null;
|
|
111
|
+
webhookTargetAway: string | null;
|
|
112
|
+
webhookTargetNight: string | null;
|
|
113
|
+
webhookTargetOff: string | null;
|
|
114
|
+
webhookCurrentHome: string | null;
|
|
115
|
+
webhookCurrentAway: string | null;
|
|
116
|
+
webhookCurrentNight: string | null;
|
|
117
|
+
webhookCurrentOff: string | null;
|
|
118
|
+
webhookCurrentWarning: string | null;
|
|
119
|
+
webhookCurrentTriggered: string | null;
|
|
120
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { Service } from 'homebridge';
|
|
2
|
+
|
|
3
|
+
/** All HomeKit services exposed by the security system accessory. */
|
|
4
|
+
export interface ServiceRegistry {
|
|
5
|
+
mainService: Service;
|
|
6
|
+
accessoryInfoService: Service;
|
|
7
|
+
|
|
8
|
+
// Trip switches
|
|
9
|
+
tripSwitchService: Service;
|
|
10
|
+
tripHomeSwitchService: Service;
|
|
11
|
+
tripAwaySwitchService: Service;
|
|
12
|
+
tripNightSwitchService: Service;
|
|
13
|
+
tripOverrideSwitchService: Service;
|
|
14
|
+
|
|
15
|
+
// Arming lock switches
|
|
16
|
+
armingLockSwitchService: Service;
|
|
17
|
+
armingLockHomeSwitchService: Service;
|
|
18
|
+
armingLockAwaySwitchService: Service;
|
|
19
|
+
armingLockNightSwitchService: Service;
|
|
20
|
+
|
|
21
|
+
// Mode switches
|
|
22
|
+
modeHomeSwitchService: Service;
|
|
23
|
+
modeAwaySwitchService: Service;
|
|
24
|
+
modeNightSwitchService: Service;
|
|
25
|
+
modeOffSwitchService: Service;
|
|
26
|
+
modeAwayExtendedSwitchService: Service;
|
|
27
|
+
modePauseSwitchService: Service;
|
|
28
|
+
|
|
29
|
+
// Audio switch
|
|
30
|
+
audioSwitchService: Service;
|
|
31
|
+
|
|
32
|
+
// Motion sensors
|
|
33
|
+
armingMotionSensorService: Service;
|
|
34
|
+
trippedMotionSensorService: Service;
|
|
35
|
+
triggeredMotionSensorService: Service;
|
|
36
|
+
triggeredResetMotionSensorService: Service;
|
|
37
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { ChildProcess } from 'child_process';
|
|
2
|
+
import type { SecurityState } from '../types/security-state-type.js';
|
|
3
|
+
|
|
4
|
+
/** Mutable runtime state shared across all handlers. */
|
|
5
|
+
export interface SystemState {
|
|
6
|
+
currentState: SecurityState;
|
|
7
|
+
targetState: SecurityState;
|
|
8
|
+
defaultState: SecurityState;
|
|
9
|
+
availableTargetStates: SecurityState[];
|
|
10
|
+
|
|
11
|
+
isArming: boolean;
|
|
12
|
+
isKnocked: boolean;
|
|
13
|
+
invalidCodeCount: number;
|
|
14
|
+
pausedCurrentState: SecurityState | null;
|
|
15
|
+
audioProcess: ChildProcess | null;
|
|
16
|
+
|
|
17
|
+
// Active timers (null = not running)
|
|
18
|
+
armTimeout: ReturnType<typeof setTimeout> | null;
|
|
19
|
+
pauseTimeout: ReturnType<typeof setTimeout> | null;
|
|
20
|
+
triggerTimeout: ReturnType<typeof setTimeout> | null;
|
|
21
|
+
doubleKnockTimeout: ReturnType<typeof setTimeout> | null;
|
|
22
|
+
resetTimeout: ReturnType<typeof setTimeout> | null;
|
|
23
|
+
trippedMotionSensorInterval: ReturnType<typeof setInterval> | null;
|
|
24
|
+
triggeredMotionSensorInterval: ReturnType<typeof setInterval> | null;
|
|
25
|
+
}
|