homebridge-securitysystem 0.0.1-matter

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 (257) hide show
  1. package/.gitattributes +1 -0
  2. package/.github/ISSUE_TEMPLATE/bug_report.yml +46 -0
  3. package/.github/ISSUE_TEMPLATE/feature-request.yml +17 -0
  4. package/.github/ISSUE_TEMPLATE/questions-answers.yml +40 -0
  5. package/.github/demo.jpg +0 -0
  6. package/.github/dependabot.yml +19 -0
  7. package/.github/release.yml +36 -0
  8. package/.github/workflows/build-package.yml +49 -0
  9. package/.github/workflows/bump-version.yml +59 -0
  10. package/.github/workflows/dependency-review.yml +26 -0
  11. package/.github/workflows/publish.yml +155 -0
  12. package/.github/workflows/stale-activity.yml +27 -0
  13. package/AGENTS.md +247 -0
  14. package/CHANGELOG.md +572 -0
  15. package/CODE_OF_CONDUCT.md +128 -0
  16. package/CONTRIBUTING.md +5 -0
  17. package/LICENSE +21 -0
  18. package/README.md +47 -0
  19. package/SECURITY.md +12 -0
  20. package/config.schema.json +934 -0
  21. package/dist/conditions/already-triggered-condition.d.ts +10 -0
  22. package/dist/conditions/already-triggered-condition.js +22 -0
  23. package/dist/conditions/already-triggered-condition.js.map +1 -0
  24. package/dist/conditions/arming-in-progress-condition.d.ts +10 -0
  25. package/dist/conditions/arming-in-progress-condition.js +21 -0
  26. package/dist/conditions/arming-in-progress-condition.js.map +1 -0
  27. package/dist/conditions/arming-lock-condition.d.ts +10 -0
  28. package/dist/conditions/arming-lock-condition.js +43 -0
  29. package/dist/conditions/arming-lock-condition.js.map +1 -0
  30. package/dist/conditions/condition.d.ts +22 -0
  31. package/dist/conditions/condition.js +19 -0
  32. package/dist/conditions/condition.js.map +1 -0
  33. package/dist/conditions/double-knock-condition.d.ts +24 -0
  34. package/dist/conditions/double-knock-condition.js +73 -0
  35. package/dist/conditions/double-knock-condition.js.map +1 -0
  36. package/dist/conditions/not-armed-condition.d.ts +10 -0
  37. package/dist/conditions/not-armed-condition.js +26 -0
  38. package/dist/conditions/not-armed-condition.js.map +1 -0
  39. package/dist/conditions/trigger-already-running-condition.d.ts +10 -0
  40. package/dist/conditions/trigger-already-running-condition.js +21 -0
  41. package/dist/conditions/trigger-already-running-condition.js.map +1 -0
  42. package/dist/constants/default-constant.d.ts +24 -0
  43. package/dist/constants/default-constant.js +27 -0
  44. package/dist/constants/default-constant.js.map +1 -0
  45. package/dist/constants/homekit-constant.d.ts +2 -0
  46. package/dist/constants/homekit-constant.js +3 -0
  47. package/dist/constants/homekit-constant.js.map +1 -0
  48. package/dist/constants/matter-constant.d.ts +21 -0
  49. package/dist/constants/matter-constant.js +61 -0
  50. package/dist/constants/matter-constant.js.map +1 -0
  51. package/dist/handlers/sensor-handler.d.ts +24 -0
  52. package/dist/handlers/sensor-handler.js +63 -0
  53. package/dist/handlers/sensor-handler.js.map +1 -0
  54. package/dist/handlers/state-handler.d.ts +49 -0
  55. package/dist/handlers/state-handler.js +204 -0
  56. package/dist/handlers/state-handler.js.map +1 -0
  57. package/dist/handlers/switch-handler.d.ts +28 -0
  58. package/dist/handlers/switch-handler.js +95 -0
  59. package/dist/handlers/switch-handler.js.map +1 -0
  60. package/dist/handlers/trip-handler.d.ts +44 -0
  61. package/dist/handlers/trip-handler.js +156 -0
  62. package/dist/handlers/trip-handler.js.map +1 -0
  63. package/dist/homekit/homekit-registrar.d.ts +12 -0
  64. package/dist/homekit/homekit-registrar.js +23 -0
  65. package/dist/homekit/homekit-registrar.js.map +1 -0
  66. package/dist/homekit/service-factory.d.ts +12 -0
  67. package/dist/homekit/service-factory.js +24 -0
  68. package/dist/homekit/service-factory.js.map +1 -0
  69. package/dist/index.d.ts +3 -0
  70. package/dist/index.js +7 -0
  71. package/dist/index.js.map +1 -0
  72. package/dist/interfaces/condition-context-interface.d.ts +14 -0
  73. package/dist/interfaces/condition-context-interface.js +2 -0
  74. package/dist/interfaces/condition-context-interface.js.map +1 -0
  75. package/dist/interfaces/hap-types-interface.d.ts +9 -0
  76. package/dist/interfaces/hap-types-interface.js +2 -0
  77. package/dist/interfaces/hap-types-interface.js.map +1 -0
  78. package/dist/interfaces/mqtt-status-payload-interface.d.ts +6 -0
  79. package/dist/interfaces/mqtt-status-payload-interface.js +2 -0
  80. package/dist/interfaces/mqtt-status-payload-interface.js.map +1 -0
  81. package/dist/interfaces/options-interface.d.ts +87 -0
  82. package/dist/interfaces/options-interface.js +2 -0
  83. package/dist/interfaces/options-interface.js.map +1 -0
  84. package/dist/interfaces/persisted-state-interface.d.ts +6 -0
  85. package/dist/interfaces/persisted-state-interface.js +2 -0
  86. package/dist/interfaces/persisted-state-interface.js.map +1 -0
  87. package/dist/interfaces/service-registry-interface.d.ts +10 -0
  88. package/dist/interfaces/service-registry-interface.js +2 -0
  89. package/dist/interfaces/service-registry-interface.js.map +1 -0
  90. package/dist/interfaces/system-state-interface.d.ts +22 -0
  91. package/dist/interfaces/system-state-interface.js +2 -0
  92. package/dist/interfaces/system-state-interface.js.map +1 -0
  93. package/dist/schemas/arming-lock-schema.d.ts +10 -0
  94. package/dist/schemas/arming-lock-schema.js +12 -0
  95. package/dist/schemas/arming-lock-schema.js.map +1 -0
  96. package/dist/schemas/error-schema.d.ts +4 -0
  97. package/dist/schemas/error-schema.js +7 -0
  98. package/dist/schemas/error-schema.js.map +1 -0
  99. package/dist/schemas/mode-request-schema.d.ts +10 -0
  100. package/dist/schemas/mode-request-schema.js +18 -0
  101. package/dist/schemas/mode-request-schema.js.map +1 -0
  102. package/dist/schemas/status-response-schema.d.ts +7 -0
  103. package/dist/schemas/status-response-schema.js +10 -0
  104. package/dist/schemas/status-response-schema.js.map +1 -0
  105. package/dist/schemas/trip-mode-request-schema.d.ts +9 -0
  106. package/dist/schemas/trip-mode-request-schema.js +24 -0
  107. package/dist/schemas/trip-mode-request-schema.js.map +1 -0
  108. package/dist/security-system-platform.d.ts +19 -0
  109. package/dist/security-system-platform.js +56 -0
  110. package/dist/security-system-platform.js.map +1 -0
  111. package/dist/security-system.d.ts +28 -0
  112. package/dist/security-system.js +169 -0
  113. package/dist/security-system.js.map +1 -0
  114. package/dist/services/command-service.d.ts +16 -0
  115. package/dist/services/command-service.js +65 -0
  116. package/dist/services/command-service.js.map +1 -0
  117. package/dist/services/configuration-service.d.ts +24 -0
  118. package/dist/services/configuration-service.js +189 -0
  119. package/dist/services/configuration-service.js.map +1 -0
  120. package/dist/services/event-bus-service.d.ts +12 -0
  121. package/dist/services/event-bus-service.js +17 -0
  122. package/dist/services/event-bus-service.js.map +1 -0
  123. package/dist/services/matter-service.d.ts +69 -0
  124. package/dist/services/matter-service.js +363 -0
  125. package/dist/services/matter-service.js.map +1 -0
  126. package/dist/services/mqtt-service.d.ts +16 -0
  127. package/dist/services/mqtt-service.js +97 -0
  128. package/dist/services/mqtt-service.js.map +1 -0
  129. package/dist/services/server-service.d.ts +28 -0
  130. package/dist/services/server-service.js +275 -0
  131. package/dist/services/server-service.js.map +1 -0
  132. package/dist/services/storage-service.d.ts +14 -0
  133. package/dist/services/storage-service.js +70 -0
  134. package/dist/services/storage-service.js.map +1 -0
  135. package/dist/services/webhook-service.d.ts +16 -0
  136. package/dist/services/webhook-service.js +68 -0
  137. package/dist/services/webhook-service.js.map +1 -0
  138. package/dist/tests/conditions.test.d.ts +1 -0
  139. package/dist/tests/conditions.test.js +175 -0
  140. package/dist/tests/conditions.test.js.map +1 -0
  141. package/dist/tests/matter-service.test.d.ts +1 -0
  142. package/dist/tests/matter-service.test.js +475 -0
  143. package/dist/tests/matter-service.test.js.map +1 -0
  144. package/dist/tests/mqtt-service.test.d.ts +1 -0
  145. package/dist/tests/mqtt-service.test.js +168 -0
  146. package/dist/tests/mqtt-service.test.js.map +1 -0
  147. package/dist/tests/sensor-handler.test.d.ts +1 -0
  148. package/dist/tests/sensor-handler.test.js +87 -0
  149. package/dist/tests/sensor-handler.test.js.map +1 -0
  150. package/dist/tests/server-service.test.d.ts +1 -0
  151. package/dist/tests/server-service.test.js +188 -0
  152. package/dist/tests/server-service.test.js.map +1 -0
  153. package/dist/tests/state-handler.test.d.ts +1 -0
  154. package/dist/tests/state-handler.test.js +276 -0
  155. package/dist/tests/state-handler.test.js.map +1 -0
  156. package/dist/tests/switch-handler.test.d.ts +1 -0
  157. package/dist/tests/switch-handler.test.js +186 -0
  158. package/dist/tests/switch-handler.test.js.map +1 -0
  159. package/dist/tests/trip-handler.test.d.ts +1 -0
  160. package/dist/tests/trip-handler.test.js +179 -0
  161. package/dist/tests/trip-handler.test.js.map +1 -0
  162. package/dist/timers/timer-manager.d.ts +31 -0
  163. package/dist/timers/timer-manager.js +118 -0
  164. package/dist/timers/timer-manager.js.map +1 -0
  165. package/dist/types/event-payload-map-type.d.ts +15 -0
  166. package/dist/types/event-payload-map-type.js +2 -0
  167. package/dist/types/event-payload-map-type.js.map +1 -0
  168. package/dist/types/event-type.d.ts +44 -0
  169. package/dist/types/event-type.js +20 -0
  170. package/dist/types/event-type.js.map +1 -0
  171. package/dist/types/matter-accessory-key-type.d.ts +7 -0
  172. package/dist/types/matter-accessory-key-type.js +2 -0
  173. package/dist/types/matter-accessory-key-type.js.map +1 -0
  174. package/dist/types/mode-type.d.ts +4 -0
  175. package/dist/types/mode-type.js +2 -0
  176. package/dist/types/mode-type.js.map +1 -0
  177. package/dist/types/origin-type.d.ts +9 -0
  178. package/dist/types/origin-type.js +11 -0
  179. package/dist/types/origin-type.js.map +1 -0
  180. package/dist/types/security-state-type.d.ts +11 -0
  181. package/dist/types/security-state-type.js +13 -0
  182. package/dist/types/security-state-type.js.map +1 -0
  183. package/dist/types/sensor-kind-type.d.ts +2 -0
  184. package/dist/types/sensor-kind-type.js +2 -0
  185. package/dist/types/sensor-kind-type.js.map +1 -0
  186. package/dist/types/service-result-type.d.ts +4 -0
  187. package/dist/types/service-result-type.js +2 -0
  188. package/dist/types/service-result-type.js.map +1 -0
  189. package/dist/utils/arming-util.d.ts +19 -0
  190. package/dist/utils/arming-util.js +24 -0
  191. package/dist/utils/arming-util.js.map +1 -0
  192. package/dist/utils/state-util.d.ts +8 -0
  193. package/dist/utils/state-util.js +29 -0
  194. package/dist/utils/state-util.js.map +1 -0
  195. package/docs/MQTT.md +50 -0
  196. package/package.json +64 -0
  197. package/src/@types/homebridge-lib.d.ts +11 -0
  198. package/src/conditions/already-triggered-condition.ts +24 -0
  199. package/src/conditions/arming-in-progress-condition.ts +23 -0
  200. package/src/conditions/arming-lock-condition.ts +50 -0
  201. package/src/conditions/condition.ts +31 -0
  202. package/src/conditions/double-knock-condition.ts +84 -0
  203. package/src/conditions/not-armed-condition.ts +30 -0
  204. package/src/conditions/trigger-already-running-condition.ts +23 -0
  205. package/src/constants/default-constant.ts +28 -0
  206. package/src/constants/homekit-constant.ts +2 -0
  207. package/src/constants/matter-constant.ts +69 -0
  208. package/src/handlers/sensor-handler.ts +78 -0
  209. package/src/handlers/state-handler.ts +257 -0
  210. package/src/handlers/switch-handler.ts +111 -0
  211. package/src/handlers/trip-handler.ts +193 -0
  212. package/src/homekit/homekit-registrar.ts +28 -0
  213. package/src/homekit/service-factory.ts +35 -0
  214. package/src/index.ts +9 -0
  215. package/src/interfaces/condition-context-interface.ts +15 -0
  216. package/src/interfaces/hap-types-interface.ts +11 -0
  217. package/src/interfaces/mqtt-status-payload-interface.ts +6 -0
  218. package/src/interfaces/options-interface.ts +116 -0
  219. package/src/interfaces/persisted-state-interface.ts +7 -0
  220. package/src/interfaces/service-registry-interface.ts +11 -0
  221. package/src/interfaces/system-state-interface.ts +25 -0
  222. package/src/schemas/arming-lock-schema.ts +12 -0
  223. package/src/schemas/error-schema.ts +7 -0
  224. package/src/schemas/mode-request-schema.ts +18 -0
  225. package/src/schemas/status-response-schema.ts +10 -0
  226. package/src/schemas/trip-mode-request-schema.ts +24 -0
  227. package/src/security-system-platform.ts +68 -0
  228. package/src/security-system.ts +199 -0
  229. package/src/services/command-service.ts +76 -0
  230. package/src/services/configuration-service.ts +224 -0
  231. package/src/services/event-bus-service.ts +21 -0
  232. package/src/services/matter-service.ts +446 -0
  233. package/src/services/mqtt-service.ts +123 -0
  234. package/src/services/server-service.ts +327 -0
  235. package/src/services/storage-service.ts +80 -0
  236. package/src/services/webhook-service.ts +77 -0
  237. package/src/tests/conditions.test.ts +212 -0
  238. package/src/tests/matter-service.test.ts +610 -0
  239. package/src/tests/mqtt-service.test.ts +231 -0
  240. package/src/tests/sensor-handler.test.ts +116 -0
  241. package/src/tests/server-service.test.ts +238 -0
  242. package/src/tests/state-handler.test.ts +371 -0
  243. package/src/tests/switch-handler.test.ts +234 -0
  244. package/src/tests/trip-handler.test.ts +244 -0
  245. package/src/timers/timer-manager.ts +141 -0
  246. package/src/types/event-payload-map-type.ts +25 -0
  247. package/src/types/event-type.ts +61 -0
  248. package/src/types/matter-accessory-key-type.ts +33 -0
  249. package/src/types/mode-type.ts +4 -0
  250. package/src/types/origin-type.ts +9 -0
  251. package/src/types/security-state-type.ts +11 -0
  252. package/src/types/sensor-kind-type.ts +2 -0
  253. package/src/types/service-result-type.ts +4 -0
  254. package/src/utils/arming-util.ts +44 -0
  255. package/src/utils/state-util.ts +32 -0
  256. package/tsconfig.json +26 -0
  257. package/vitest.config.ts +8 -0
@@ -0,0 +1,169 @@
1
+ import { SecurityState } from './types/security-state-type.js';
2
+ import { OriginType } from './types/origin-type.js';
3
+ import { ConfigurationService } from './services/configuration-service.js';
4
+ import { stateToMode, modeToState } from './utils/state-util.js';
5
+ import { EventBusService } from './services/event-bus-service.js';
6
+ import { EventType } from './types/event-type.js';
7
+ import { StorageService } from './services/storage-service.js';
8
+ import { WebhookService } from './services/webhook-service.js';
9
+ import { CommandService } from './services/command-service.js';
10
+ import { MqttService } from './services/mqtt-service.js';
11
+ import { MatterService } from './services/matter-service.js';
12
+ import { ServerService } from './services/server-service.js';
13
+ import { StateHandler } from './handlers/state-handler.js';
14
+ import { TripHandler } from './handlers/trip-handler.js';
15
+ import { SwitchHandler } from './handlers/switch-handler.js';
16
+ import { SensorHandler } from './handlers/sensor-handler.js';
17
+ import { buildServiceRegistry, buildServiceList } from './homekit/service-factory.js';
18
+ import { HomeKitRegistrar } from './homekit/homekit-registrar.js';
19
+ import { TimerManager } from './timers/timer-manager.js';
20
+ export class SecuritySystem {
21
+ log;
22
+ api;
23
+ accessory;
24
+ options;
25
+ state;
26
+ svcs;
27
+ serviceList;
28
+ bus;
29
+ stateHandler;
30
+ tripHandler;
31
+ switchHandler;
32
+ sensorHandler;
33
+ storageService;
34
+ matterService;
35
+ constructor(log, config, api, accessory) {
36
+ this.log = log;
37
+ this.api = api;
38
+ this.accessory = accessory;
39
+ const Char = api.hap.Characteristic;
40
+ const Svc = api.hap.Service;
41
+ this.options = new ConfigurationService(log, config).options;
42
+ const defaultState = modeToState(this.options.defaultMode);
43
+ this.state = this.buildState(defaultState === -1 ? SecurityState.OFF : defaultState);
44
+ this.svcs = buildServiceRegistry(Svc, Char, this.options);
45
+ this.state.availableTargetStates = this.calcAvailableTargetStates();
46
+ // Sync main service initial values.
47
+ this.svcs.mainService.getCharacteristic(Char.SecuritySystemTargetState).value = this.state.targetState;
48
+ this.svcs.mainService.getCharacteristic(Char.SecuritySystemCurrentState).value = this.state.currentState;
49
+ this.svcs.mainService
50
+ .setCharacteristic(Char.ConfiguredName, this.options.name)
51
+ .getCharacteristic(Char.SecuritySystemTargetState)
52
+ .setProps({ validValues: this.state.availableTargetStates });
53
+ // Services.
54
+ this.bus = new EventBusService();
55
+ this.storageService = new StorageService(log, this.options, api.user.storagePath());
56
+ const timerManager = new TimerManager(log);
57
+ // Handlers — construction order matters: sensorHandler first (leaf), then stateHandler,
58
+ // then switchHandler (depends on stateHandler), then tripHandler.
59
+ this.sensorHandler = new SensorHandler(log, this.bus);
60
+ this.stateHandler = new StateHandler(this.svcs, this.state, this.options, Char, log, this.bus, this.storageService, timerManager, this.sensorHandler);
61
+ this.switchHandler = new SwitchHandler(this.state, this.options, log, timerManager, this.stateHandler);
62
+ this.tripHandler = new TripHandler(this.state, this.options, log, this.bus, this.sensorHandler, timerManager);
63
+ // Wire bus listeners for cross-handler coordination (no more circular constructor deps).
64
+ this.bus.on(EventType.TRIGGER_FIRED, ({ origin }) => {
65
+ this.stateHandler.setCurrentState(SecurityState.TRIGGERED, origin);
66
+ });
67
+ this.bus.on(EventType.TRIP_CANCELLED, ({ stateChanged }) => {
68
+ if (this.state.currentState === SecurityState.TRIGGERED && !stateChanged) {
69
+ this.stateHandler.updateTargetState(SecurityState.OFF, OriginType.INTERNAL, 0);
70
+ }
71
+ else {
72
+ this.stateHandler.resetTimers();
73
+ }
74
+ });
75
+ // Attach side-effect listeners.
76
+ const webhookSvc = new WebhookService(log, this.options, this.state);
77
+ const commandSvc = new CommandService(log, this.options, this.state);
78
+ webhookSvc.attachToBus(this.bus);
79
+ commandSvc.attachToBus(this.bus);
80
+ const mqttSvc = new MqttService(log, this.options, this.state);
81
+ mqttSvc.attachToBus(this.bus);
82
+ this.api.on('shutdown', () => mqttSvc.disconnect());
83
+ // Publish the optional switch/sensor accessories over Matter (HAP keeps the
84
+ // main SecuritySystem service and the motion sensors). Registration happens
85
+ // on the platform after didFinishLaunching, via setupMatterAccessories().
86
+ this.matterService = new MatterService(log, this.options, api, this.state, this.switchHandler, this.tripHandler, this.sensorHandler);
87
+ this.matterService.attachToBus(this.bus);
88
+ // Register HomeKit characteristic handlers.
89
+ new HomeKitRegistrar(this.svcs, this.state, this.stateHandler)
90
+ .register(Char);
91
+ // Build the exposed service list and host it on the platform accessory.
92
+ this.serviceList = buildServiceList(this.svcs);
93
+ this.populateAccessory(Svc);
94
+ this.accessory.on('identify', () => this.log.info('Identify'));
95
+ // Startup tasks.
96
+ this.logStartup();
97
+ const syncModeSwitches = () => {
98
+ this.bus.emit(EventType.RESET_MODE_SWITCHES, {});
99
+ this.bus.emit(EventType.UPDATE_MODE_SWITCHES, {});
100
+ };
101
+ if (this.options.saveState) {
102
+ this.storageService.init().then(() => this.storageService.load(this.state).then(() => {
103
+ this.svcs.mainService.updateCharacteristic(Char.SecuritySystemTargetState, this.state.targetState);
104
+ this.svcs.mainService.updateCharacteristic(Char.SecuritySystemCurrentState, this.state.currentState);
105
+ this.stateHandler.logMode('Current', this.state.currentState);
106
+ syncModeSwitches();
107
+ }));
108
+ }
109
+ else {
110
+ syncModeSwitches();
111
+ }
112
+ if (this.options.serverPort !== null) {
113
+ new ServerService(log, this.options, this.state, this.stateHandler, this.tripHandler, this.switchHandler).start();
114
+ }
115
+ }
116
+ // ── Public API ─────────────────────────────────────────────────────────────
117
+ /**
118
+ * Registers all configured switch/sensor accessories over Matter.
119
+ * No-op when Matter is disabled on the bridge.
120
+ */
121
+ setupMatterAccessories(cachedAccessories) {
122
+ return this.matterService.registerAccessories(cachedAccessories);
123
+ }
124
+ // ── Private helpers ────────────────────────────────────────────────────────
125
+ /** Replaces the accessory's auto-created information service and adds all exposed services. */
126
+ populateAccessory(Svc) {
127
+ const existingInfoService = this.accessory.getService(Svc.AccessoryInformation);
128
+ if (existingInfoService) {
129
+ this.accessory.removeService(existingInfoService);
130
+ }
131
+ this.accessory.updateDisplayName(this.options.name);
132
+ for (const service of this.serviceList) {
133
+ this.accessory.addService(service);
134
+ }
135
+ }
136
+ buildState(defaultState) {
137
+ return {
138
+ currentState: defaultState,
139
+ targetState: defaultState,
140
+ defaultState,
141
+ availableTargetStates: [],
142
+ isArming: false,
143
+ isTripping: false,
144
+ isKnocked: false,
145
+ serverAuthenticationAttempts: 0,
146
+ pausedCurrentState: null,
147
+ armingLocks: { global: false, home: false, away: false, night: false },
148
+ modeAwayExtended: false,
149
+ };
150
+ }
151
+ calcAvailableTargetStates() {
152
+ const all = [SecurityState.HOME, SecurityState.AWAY, SecurityState.NIGHT, SecurityState.OFF];
153
+ const disabled = this.options.disabledModes.map(m => modeToState(m.toLowerCase()));
154
+ return all.filter(s => !disabled.includes(s));
155
+ }
156
+ logStartup() {
157
+ if (this.options.testMode) {
158
+ this.log.warn('Test Mode');
159
+ }
160
+ stateToMode(this.state.defaultState);
161
+ this.stateHandler.logMode('Default', this.state.defaultState);
162
+ this.log.info(`Arm delay (${this.options.armSeconds}s)`);
163
+ this.log.info(`Trigger delay (${this.options.triggerSeconds}s)`);
164
+ if (this.options.proxyMode) {
165
+ this.log.info('Proxy mode (Enabled)');
166
+ }
167
+ }
168
+ }
169
+ //# sourceMappingURL=security-system.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"security-system.js","sourceRoot":"","sources":["../src/security-system.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ import type { Logging } from 'homebridge';
2
+ import { SecurityState } from '../types/security-state-type.js';
3
+ import { OriginType } from '../types/origin-type.js';
4
+ import type { SecuritySystemOptions } from '../interfaces/options-interface.js';
5
+ import type { SystemState } from '../interfaces/system-state-interface.js';
6
+ import type { EventBusService } from './event-bus-service.js';
7
+ /** Spawns shell commands in response to state-machine events. */
8
+ export declare class CommandService {
9
+ private readonly log;
10
+ private readonly options;
11
+ private readonly state;
12
+ constructor(log: Logging, options: SecuritySystemOptions, state: SystemState);
13
+ attachToBus(bus: EventBusService): void;
14
+ execute(type: string, stateOrMode: SecurityState | string, origin: OriginType): void;
15
+ private resolveCommand;
16
+ }
@@ -0,0 +1,65 @@
1
+ import { spawn } from 'child_process';
2
+ import { SecurityState } from '../types/security-state-type.js';
3
+ import { OriginType } from '../types/origin-type.js';
4
+ import { stateToMode } from '../utils/state-util.js';
5
+ import { EventType } from '../types/event-type.js';
6
+ /** Spawns shell commands in response to state-machine events. */
7
+ export class CommandService {
8
+ log;
9
+ options;
10
+ state;
11
+ constructor(log, options, state) {
12
+ this.log = log;
13
+ this.options = options;
14
+ this.state = state;
15
+ }
16
+ attachToBus(bus) {
17
+ bus.on(EventType.TARGET_CHANGED, ({ state, origin }) => {
18
+ this.execute('target', state, origin);
19
+ });
20
+ bus.on(EventType.CURRENT_CHANGED, ({ state, origin }) => {
21
+ this.execute('current', state, origin);
22
+ });
23
+ bus.on(EventType.WARNING, ({ origin }) => {
24
+ this.execute('current', 'warning', origin);
25
+ });
26
+ }
27
+ execute(type, stateOrMode, origin) {
28
+ if (this.options.proxyMode && origin === OriginType.EXTERNAL) {
29
+ this.log.debug('Command bypassed (proxy mode).');
30
+ return;
31
+ }
32
+ let command = this.resolveCommand(type, stateOrMode);
33
+ if (!command) {
34
+ this.log.debug(`Command for ${type}/${stateOrMode} not set.`);
35
+ return;
36
+ }
37
+ const currentMode = stateToMode(this.state.currentState);
38
+ command = command.replace('${currentMode}', currentMode);
39
+ const proc = spawn(command, { shell: true });
40
+ proc.stdout.on('data', (data) => {
41
+ this.log.info(`Command output: ${data.toString().trim()}`);
42
+ });
43
+ proc.stderr.on('data', (data) => {
44
+ this.log.error(`Command failed (${command})\n${data.toString().trim()}`);
45
+ });
46
+ }
47
+ resolveCommand(type, stateOrMode) {
48
+ const s = stateOrMode;
49
+ const o = this.options;
50
+ if (s === 'warning') {
51
+ return o.commandCurrentWarning;
52
+ }
53
+ switch (s) {
54
+ case SecurityState.TRIGGERED: return o.commandCurrentTriggered;
55
+ case SecurityState.HOME: return type === 'current' ? o.commandCurrentHome : o.commandTargetHome;
56
+ case SecurityState.AWAY: return type === 'current' ? o.commandCurrentAway : o.commandTargetAway;
57
+ case SecurityState.NIGHT: return type === 'current' ? o.commandCurrentNight : o.commandTargetNight;
58
+ case SecurityState.OFF: return type === 'current' ? o.commandCurrentOff : o.commandTargetOff;
59
+ default:
60
+ this.log.error(`Unknown command state (${s})`);
61
+ return null;
62
+ }
63
+ }
64
+ }
65
+ //# sourceMappingURL=command-service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"command-service.js","sourceRoot":"","sources":["../../src/services/command-service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ import type { Logging } from 'homebridge';
2
+ import type { SecuritySystemOptions } from '../interfaces/options-interface.js';
3
+ type RawConfig = Record<string, unknown>;
4
+ /**
5
+ * Centralises all configuration parsing, validation, and normalisation.
6
+ * Construct with the raw Homebridge config object; access the fully-typed
7
+ * result via the `options` property.
8
+ */
9
+ export declare class ConfigurationService {
10
+ private readonly log;
11
+ readonly options: SecuritySystemOptions;
12
+ constructor(log: Logging, raw: RawConfig);
13
+ private isSet;
14
+ private str;
15
+ private num;
16
+ private bool;
17
+ private strArr;
18
+ /** Rewrites deprecated config keys to their current equivalents in-place. */
19
+ private applyDeprecations;
20
+ private parse;
21
+ private validate;
22
+ private normalize;
23
+ }
24
+ export {};
@@ -0,0 +1,189 @@
1
+ import { DEFAULTS } from '../constants/default-constant.js';
2
+ /**
3
+ * Centralises all configuration parsing, validation, and normalisation.
4
+ * Construct with the raw Homebridge config object; access the fully-typed
5
+ * result via the `options` property.
6
+ */
7
+ export class ConfigurationService {
8
+ log;
9
+ options;
10
+ constructor(log, raw) {
11
+ this.log = log;
12
+ log.info('Config', JSON.stringify(raw));
13
+ this.applyDeprecations(raw);
14
+ this.options = this.parse(raw);
15
+ this.validate(this.options);
16
+ this.normalize(this.options);
17
+ log.info('Options', JSON.stringify(this.options));
18
+ }
19
+ // ── Private parsing helpers ─────────────────────────────────────────────────
20
+ isSet(value) {
21
+ if (value === undefined || value === null) {
22
+ return false;
23
+ }
24
+ if (typeof value === 'string' && (value.trim() === '' || value === 'null')) {
25
+ return false;
26
+ }
27
+ return true;
28
+ }
29
+ str(raw, key) {
30
+ return this.isSet(raw[key]) ? String(raw[key]) : null;
31
+ }
32
+ num(raw, key) {
33
+ const v = raw[key];
34
+ if (!this.isSet(v)) {
35
+ return null;
36
+ }
37
+ const n = Number(v);
38
+ return isNaN(n) ? null : n;
39
+ }
40
+ bool(raw, key, def) {
41
+ return this.isSet(raw[key]) ? Boolean(raw[key]) : def;
42
+ }
43
+ strArr(raw, key) {
44
+ return Array.isArray(raw[key]) ? raw[key].map(String) : [];
45
+ }
46
+ // ── Deprecation migration ───────────────────────────────────────────────────
47
+ /** Rewrites deprecated config keys to their current equivalents in-place. */
48
+ applyDeprecations(raw) {
49
+ const renames = {
50
+ siren_switch: 'trip_switch',
51
+ siren_override_switch: 'trip_override_switch',
52
+ siren_mode_switches: 'trip_mode_switches',
53
+ };
54
+ for (const [oldKey, newKey] of Object.entries(renames)) {
55
+ if (this.isSet(raw[oldKey]) && !this.isSet(raw[newKey])) {
56
+ this.log.warn(`Config: '${oldKey}' is deprecated, use '${newKey}' instead.`);
57
+ raw[newKey] = raw[oldKey];
58
+ }
59
+ }
60
+ }
61
+ // ── Core parsing ────────────────────────────────────────────────────────────
62
+ parse(raw) {
63
+ return {
64
+ name: this.str(raw, 'name') ?? DEFAULTS.NAME,
65
+ serialNumber: this.str(raw, 'serial_number') ?? DEFAULTS.SERIAL_NUMBER,
66
+ defaultMode: this.str(raw, 'default_mode') ?? DEFAULTS.DEFAULT_MODE,
67
+ armSeconds: this.num(raw, 'arm_seconds') ?? DEFAULTS.ARM_SECONDS,
68
+ triggerSeconds: this.num(raw, 'trigger_seconds') ?? DEFAULTS.TRIGGER_SECONDS,
69
+ resetMinutes: this.num(raw, 'reset_minutes') ?? DEFAULTS.RESET_MINUTES,
70
+ saveState: this.bool(raw, 'save_state', false),
71
+ proxyMode: this.bool(raw, 'proxy_mode', false),
72
+ testMode: this.bool(raw, 'test_mode', false),
73
+ // Switch display names
74
+ tripSwitchName: this.str(raw, 'trip_switch_name') ?? DEFAULTS.TRIP_SWITCH_NAME,
75
+ tripHomeSwitchName: this.str(raw, 'trip_home_switch_name') ?? DEFAULTS.TRIP_HOME_SWITCH_NAME,
76
+ tripAwaySwitchName: this.str(raw, 'trip_away_switch_name') ?? DEFAULTS.TRIP_AWAY_SWITCH_NAME,
77
+ tripNightSwitchName: this.str(raw, 'trip_night_switch_name') ?? DEFAULTS.TRIP_NIGHT_SWITCH_NAME,
78
+ tripOverrideSwitchName: this.str(raw, 'trip_override_switch_name') ?? DEFAULTS.TRIP_OVERRIDE_SWITCH_NAME,
79
+ modeHomeSwitchName: this.str(raw, 'mode_home_switch_name') ?? DEFAULTS.MODE_HOME_SWITCH_NAME,
80
+ modeAwaySwitchName: this.str(raw, 'mode_away_switch_name') ?? DEFAULTS.MODE_AWAY_SWITCH_NAME,
81
+ modeNightSwitchName: this.str(raw, 'mode_night_switch_name') ?? DEFAULTS.MODE_NIGHT_SWITCH_NAME,
82
+ modeOffSwitchName: this.str(raw, 'mode_off_switch_name') ?? DEFAULTS.MODE_OFF_SWITCH_NAME,
83
+ modeAwayExtendedSwitchName: this.str(raw, 'mode_away_extended_switch_name') ?? DEFAULTS.MODE_AWAY_EXTENDED_SWITCH_NAME,
84
+ modePauseSwitchName: this.str(raw, 'mode_pause_switch_name') ?? DEFAULTS.MODE_PAUSE_SWITCH_NAME,
85
+ // Behaviour toggles
86
+ overrideOff: this.bool(raw, 'override_off', false),
87
+ resetOffFlow: this.bool(raw, 'reset_off_flow', false),
88
+ disabledModes: this.strArr(raw, 'disabled_modes'),
89
+ // Per-mode arm delays
90
+ homeArmSeconds: this.num(raw, 'home_arm_seconds'),
91
+ awayArmSeconds: this.num(raw, 'away_arm_seconds'),
92
+ nightArmSeconds: this.num(raw, 'night_arm_seconds'),
93
+ // Per-mode trigger delays
94
+ homeTriggerSeconds: this.num(raw, 'home_trigger_seconds'),
95
+ awayTriggerSeconds: this.num(raw, 'away_trigger_seconds'),
96
+ nightTriggerSeconds: this.num(raw, 'night_trigger_seconds'),
97
+ // Trip switches
98
+ tripSwitch: this.bool(raw, 'trip_switch', false),
99
+ tripOverrideSwitch: this.bool(raw, 'trip_override_switch', false),
100
+ tripModeSwitches: this.bool(raw, 'trip_mode_switches', true),
101
+ // Arming lock
102
+ armingLockSwitch: this.bool(raw, 'arming_lock_switch', false),
103
+ armingLockSwitches: this.bool(raw, 'arming_lock_switches', false),
104
+ // Motion sensors
105
+ armingMotionSensor: this.bool(raw, 'arming_sensor', false),
106
+ trippedMotionSensor: this.bool(raw, 'tripped_sensor', false),
107
+ trippedMotionSensorSeconds: this.num(raw, 'tripped_sensor_seconds') ?? DEFAULTS.TRIPPED_SENSOR_SECONDS,
108
+ resetSensor: this.bool(raw, 'reset_sensor', false),
109
+ // Mode switches
110
+ modeSwitches: this.bool(raw, 'mode_switches', false),
111
+ modeOffSwitch: this.bool(raw, 'mode_off_switch', false),
112
+ modePauseSwitch: this.bool(raw, 'mode_pause_switch', false),
113
+ pauseMinutes: this.num(raw, 'pause_minutes') ?? DEFAULTS.PAUSE_MINUTES,
114
+ modeAwayExtendedSwitch: this.bool(raw, 'mode_away_extended_switch', false),
115
+ modeAwayExtendedSwitchTriggerSeconds: this.num(raw, 'mode_away_extended_switch_trigger_seconds'),
116
+ // Double-knock
117
+ doubleKnock: this.bool(raw, 'double_knock', false),
118
+ doubleKnockSeconds: this.num(raw, 'double_knock_seconds') ?? DEFAULTS.DOUBLE_KNOCK_SECONDS,
119
+ doubleKnockModes: this.strArr(raw, 'double_knock_modes'),
120
+ homeDoubleKnockSeconds: this.num(raw, 'home_double_knock_seconds'),
121
+ awayDoubleKnockSeconds: this.num(raw, 'away_double_knock_seconds'),
122
+ nightDoubleKnockSeconds: this.num(raw, 'night_double_knock_seconds'),
123
+ // Custom trip mode switches
124
+ tripHomeSwitches: Array.isArray(raw.trip_home_switches)
125
+ ? raw.trip_home_switches
126
+ : [],
127
+ tripAwaySwitches: Array.isArray(raw.trip_away_switches)
128
+ ? raw.trip_away_switches
129
+ : [],
130
+ tripNightSwitches: Array.isArray(raw.trip_night_switches)
131
+ ? raw.trip_night_switches
132
+ : [],
133
+ // Server
134
+ serverPort: this.num(raw, 'server_port'),
135
+ // TODO: Remove serverCode fallback in future major version
136
+ serverApiKey: this.str(raw, 'server_api_key') ?? (this.num(raw, 'server_code') !== null ? String(this.num(raw, 'server_code')) : null),
137
+ // Shell commands
138
+ commandTargetHome: this.str(raw, 'command_target_home'),
139
+ commandTargetAway: this.str(raw, 'command_target_away'),
140
+ commandTargetNight: this.str(raw, 'command_target_night'),
141
+ commandTargetOff: this.str(raw, 'command_target_off'),
142
+ commandCurrentHome: this.str(raw, 'command_current_home'),
143
+ commandCurrentAway: this.str(raw, 'command_current_away'),
144
+ commandCurrentNight: this.str(raw, 'command_current_night'),
145
+ commandCurrentOff: this.str(raw, 'command_current_off'),
146
+ commandCurrentWarning: this.str(raw, 'command_current_warning'),
147
+ commandCurrentTriggered: this.str(raw, 'command_current_triggered'),
148
+ // Webhooks
149
+ webhookTargetHome: this.str(raw, 'webhook_target_home'),
150
+ webhookTargetAway: this.str(raw, 'webhook_target_away'),
151
+ webhookTargetNight: this.str(raw, 'webhook_target_night'),
152
+ webhookTargetOff: this.str(raw, 'webhook_target_off'),
153
+ webhookCurrentHome: this.str(raw, 'webhook_current_home'),
154
+ webhookCurrentAway: this.str(raw, 'webhook_current_away'),
155
+ webhookCurrentNight: this.str(raw, 'webhook_current_night'),
156
+ webhookCurrentOff: this.str(raw, 'webhook_current_off'),
157
+ webhookCurrentWarning: this.str(raw, 'webhook_current_warning'),
158
+ webhookCurrentTriggered: this.str(raw, 'webhook_current_triggered'),
159
+ // MQTT
160
+ mqttBroker: this.str(raw, 'mqtt_broker'),
161
+ mqttUsername: this.str(raw, 'mqtt_username'),
162
+ mqttPassword: this.str(raw, 'mqtt_password'),
163
+ mqttTopic: this.str(raw, 'mqtt_topic') ?? DEFAULTS.MQTT_TOPIC,
164
+ mqttClientId: this.str(raw, 'mqtt_client_id'),
165
+ };
166
+ }
167
+ // ── Post-parse validation ───────────────────────────────────────────────────
168
+ validate(opts) {
169
+ if (opts.resetMinutes === 0) {
170
+ this.log.error('\'reset_minutes\' must be at least 1. Defaulting to 1.');
171
+ opts.resetMinutes = 1;
172
+ }
173
+ if (opts.serverPort !== null && (opts.serverPort < 0 || opts.serverPort > 65535)) {
174
+ this.log.error('\'server_port\' must be between 0 and 65535.');
175
+ }
176
+ if (opts.mqttBroker !== null && !/^mqtts?:\/\//.test(opts.mqttBroker)) {
177
+ this.log.warn('\'mqtt_broker\' should start with mqtt:// or mqtts://');
178
+ }
179
+ }
180
+ // ── Post-parse normalisation ────────────────────────────────────────────────
181
+ normalize(opts) {
182
+ opts.defaultMode = opts.defaultMode.toLowerCase();
183
+ if (opts.testMode) {
184
+ opts.webhookCurrentTriggered = null;
185
+ opts.commandCurrentTriggered = null;
186
+ }
187
+ }
188
+ }
189
+ //# sourceMappingURL=configuration-service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"configuration-service.js","sourceRoot":"","sources":["../../src/services/configuration-service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import { EventEmitter } from 'events';
2
+ import { EventType } from '../types/event-type.js';
3
+ import type { EventPayloadMap } from '../types/event-payload-map-type.js';
4
+ /**
5
+ * Typed event bus used to decouple side-effect services (commands,
6
+ * webhooks, storage) from the core state-machine handlers.
7
+ */
8
+ export declare class EventBusService extends EventEmitter {
9
+ emit<K extends EventType>(event: K, payload: EventPayloadMap[K]): boolean;
10
+ on<K extends EventType>(event: K, listener: (payload: EventPayloadMap[K]) => void): this;
11
+ off<K extends EventType>(event: K, listener: (payload: EventPayloadMap[K]) => void): this;
12
+ }
@@ -0,0 +1,17 @@
1
+ import { EventEmitter } from 'events';
2
+ /**
3
+ * Typed event bus used to decouple side-effect services (commands,
4
+ * webhooks, storage) from the core state-machine handlers.
5
+ */
6
+ export class EventBusService extends EventEmitter {
7
+ emit(event, payload) {
8
+ return super.emit(event, payload);
9
+ }
10
+ on(event, listener) {
11
+ return super.on(event, listener);
12
+ }
13
+ off(event, listener) {
14
+ return super.off(event, listener);
15
+ }
16
+ }
17
+ //# sourceMappingURL=event-bus-service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-bus-service.js","sourceRoot":"","sources":["../../src/services/event-bus-service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AAItC;;;GAGG;AACH,MAAM,OAAO,eAAgB,SAAQ,YAAY;IAC/C,IAAI,CAAsB,KAAQ,EAAE,OAA2B;QAC7D,OAAO,KAAK,CAAC,IAAI,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;IACpC,CAAC;IAED,EAAE,CAAsB,KAAQ,EAAE,QAA+C;QAC/E,OAAO,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;IACnC,CAAC;IAED,GAAG,CAAsB,KAAQ,EAAE,QAA+C;QAChF,OAAO,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;IACpC,CAAC;CACF"}
@@ -0,0 +1,69 @@
1
+ import type { API, Logging, MatterAccessory } from 'homebridge';
2
+ import type { SensorHandler } from '../handlers/sensor-handler.js';
3
+ import type { SwitchHandler } from '../handlers/switch-handler.js';
4
+ import type { TripHandler } from '../handlers/trip-handler.js';
5
+ import type { SecuritySystemOptions } from '../interfaces/options-interface.js';
6
+ import type { SystemState } from '../interfaces/system-state-interface.js';
7
+ import type { EventBusService } from './event-bus-service.js';
8
+ /**
9
+ * Publishes the optional switch and sensor accessories over Matter (HAP keeps
10
+ * the main SecuritySystem service and the motion sensors). Switches are
11
+ * Matter-only. The security system has no Matter device type, so every control
12
+ * is exposed as an OnOffSwitch and every sensor as a MotionSensor.
13
+ *
14
+ * Identities follow the `<device-type>-<index>` convention (`switch-1`,
15
+ * `motion-sensor-2`, …) and are fed through `api.matter.uuid.generate()` to
16
+ * produce stable UUIDs. Commands from the Matter controller call straight into
17
+ * the existing handlers; state changes reach it through bus events and
18
+ * `updateAccessoryState()`, mirroring the HAP characteristic updates.
19
+ */
20
+ export declare class MatterService {
21
+ private readonly log;
22
+ private readonly options;
23
+ private readonly api;
24
+ private readonly state;
25
+ private readonly switchHandler;
26
+ private readonly tripHandler;
27
+ private readonly sensorHandler;
28
+ private readonly accessoryUuidByKey;
29
+ private readonly sensorUuidByKind;
30
+ private readonly pushedSwitchStateByKey;
31
+ private readonly pushedSensorStateByKind;
32
+ private matter;
33
+ constructor(log: Logging, options: SecuritySystemOptions, api: API, state: SystemState, switchHandler: SwitchHandler, tripHandler: TripHandler, sensorHandler: SensorHandler);
34
+ attachToBus(bus: EventBusService): void;
35
+ /**
36
+ * Registers every configured Matter accessory and removes cached ones that are
37
+ * no longer configured. Accessories restored from Homebridge's cache are
38
+ * matched by UUID and adopted by the Matter server, so they are not
39
+ * re-registered. No-op when Matter is disabled on the bridge.
40
+ */
41
+ registerAccessories(cachedAccessories: Map<string, MatterAccessory>): Promise<void>;
42
+ private addModeSwitches;
43
+ private addTripSwitches;
44
+ private addArmingLockSwitches;
45
+ private addMotionSensors;
46
+ private addOnOffSwitch;
47
+ /** Sensors declare no handlers — they only push readings with updateAccessoryState. */
48
+ private addMotionSensor;
49
+ /**
50
+ * Runs a controller command, translating failures into Matter status errors:
51
+ * a blocked action throws a specific status class, and any unexpected error
52
+ * from the underlying handler becomes a generic Failure instead of escaping
53
+ * as an untyped error (matter-errors best practice).
54
+ */
55
+ private runCommand;
56
+ private throwIfBlocked;
57
+ private rethrowAsMatterError;
58
+ private pushModeSwitchesOff;
59
+ private pushModeSwitchForTargetState;
60
+ private modeSwitchKeyForTarget;
61
+ private pushTripSwitchesOff;
62
+ private pushLockSwitches;
63
+ private pushSwitch;
64
+ private pushSensorState;
65
+ /** Syncs every registered switch/sensor to its real state after registration. */
66
+ private syncInitialState;
67
+ private pushAccessoryState;
68
+ private uuidFor;
69
+ }