homebridge-lametric-time-deadbone 0.1.0-alpha.0

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 (55) hide show
  1. package/LICENSE +17 -0
  2. package/README.md +219 -0
  3. package/config.schema.json +295 -0
  4. package/dist/accessories/message-accessory.d.ts +7 -0
  5. package/dist/accessories/message-accessory.js +7 -0
  6. package/dist/accessories/message-accessory.js.map +1 -0
  7. package/dist/accessories/notification-switch.d.ts +13 -0
  8. package/dist/accessories/notification-switch.js +43 -0
  9. package/dist/accessories/notification-switch.js.map +1 -0
  10. package/dist/config/defaults.d.ts +28 -0
  11. package/dist/config/defaults.js +40 -0
  12. package/dist/config/defaults.js.map +1 -0
  13. package/dist/config/types.d.ts +69 -0
  14. package/dist/config/types.js +2 -0
  15. package/dist/config/types.js.map +1 -0
  16. package/dist/config/validation.d.ts +6 -0
  17. package/dist/config/validation.js +233 -0
  18. package/dist/config/validation.js.map +1 -0
  19. package/dist/index.d.ts +3 -0
  20. package/dist/index.js +6 -0
  21. package/dist/index.js.map +1 -0
  22. package/dist/lametric/client.d.ts +18 -0
  23. package/dist/lametric/client.js +112 -0
  24. package/dist/lametric/client.js.map +1 -0
  25. package/dist/lametric/errors.d.ts +17 -0
  26. package/dist/lametric/errors.js +35 -0
  27. package/dist/lametric/errors.js.map +1 -0
  28. package/dist/lametric/notification-builder.d.ts +8 -0
  29. package/dist/lametric/notification-builder.js +37 -0
  30. package/dist/lametric/notification-builder.js.map +1 -0
  31. package/dist/lametric/types.d.ts +26 -0
  32. package/dist/lametric/types.js +2 -0
  33. package/dist/lametric/types.js.map +1 -0
  34. package/dist/platform.d.ts +27 -0
  35. package/dist/platform.js +157 -0
  36. package/dist/platform.js.map +1 -0
  37. package/dist/services/queue.d.ts +32 -0
  38. package/dist/services/queue.js +96 -0
  39. package/dist/services/queue.js.map +1 -0
  40. package/dist/services/rate-limiter.d.ts +6 -0
  41. package/dist/services/rate-limiter.js +16 -0
  42. package/dist/services/rate-limiter.js.map +1 -0
  43. package/dist/services/template-engine.d.ts +9 -0
  44. package/dist/services/template-engine.js +13 -0
  45. package/dist/services/template-engine.js.map +1 -0
  46. package/dist/settings.d.ts +3 -0
  47. package/dist/settings.js +4 -0
  48. package/dist/settings.js.map +1 -0
  49. package/dist/utils/logger.d.ts +10 -0
  50. package/dist/utils/logger.js +23 -0
  51. package/dist/utils/logger.js.map +1 -0
  52. package/dist/utils/security.d.ts +6 -0
  53. package/dist/utils/security.js +31 -0
  54. package/dist/utils/security.js.map +1 -0
  55. package/package.json +61 -0
package/LICENSE ADDED
@@ -0,0 +1,17 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ Copyright 2026 Thierry Lubrez
6
+
7
+ Licensed under the Apache License, Version 2.0 (the "License");
8
+ you may not use this file except in compliance with the License.
9
+ You may obtain a copy of the License at
10
+
11
+ http://www.apache.org/licenses/LICENSE-2.0
12
+
13
+ Unless required by applicable law or agreed to in writing, software
14
+ distributed under the License is distributed on an "AS IS" BASIS,
15
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ See the License for the specific language governing permissions and
17
+ limitations under the License.
package/README.md ADDED
@@ -0,0 +1,219 @@
1
+ # homebridge-lametric-time-deadbone
2
+
3
+ Dynamic Homebridge platform plugin for sending local notifications to one or more LaMetric TIME clocks.
4
+
5
+ > Alpha release: this plugin is versioned as `0.1.0-alpha.0`. It has automated tests and compiles, but it still needs validation with real LaMetric TIME hardware before being considered stable.
6
+
7
+ The plugin uses the LaMetric Device API v2 local endpoint:
8
+
9
+ ```text
10
+ POST http://<device-host>:8080/api/v2/device/notifications
11
+ ```
12
+
13
+ HTTPS on port `4343` can be configured, but the plugin does not disable TLS verification globally. If your device uses a self-signed local certificate and Node rejects it, prefer HTTP on a trusted local network for now.
14
+
15
+ ## Compatibility
16
+
17
+ - Homebridge: `^1.6.0 || ^2.0.0`
18
+ - Node.js: `^22.12.0 || ^24.0.0`
19
+ - Plugin type: dynamic platform
20
+ - Module format: ESM
21
+
22
+ Homebridge 2 compatibility is based on the official dynamic platform model and avoids deprecated callback characteristics by using `onGet` and `onSet`.
23
+
24
+ ## Installation
25
+
26
+ ### Homebridge UI
27
+
28
+ After the package is published to npm, install it from the Homebridge UI:
29
+
30
+ 1. Open Homebridge UI.
31
+ 2. Go to **Plugins**.
32
+ 3. Search for `homebridge-lametric-time-deadbone`.
33
+ 4. Click **Install**.
34
+ 5. Restart Homebridge.
35
+
36
+ ### npm
37
+
38
+ ```sh
39
+ npm install -g homebridge-lametric-time-deadbone
40
+ ```
41
+
42
+ ### Local Development Install
43
+
44
+ ```sh
45
+ npm install
46
+ npm run build
47
+ npm link
48
+ ```
49
+
50
+ ## LaMetric Local API Key
51
+
52
+ Enable or retrieve the local Device API key from your LaMetric developer/device settings. The plugin authenticates with HTTP Basic auth:
53
+
54
+ - user: `dev`
55
+ - password: your local LaMetric API key
56
+
57
+ The key is configured as a Homebridge UI password field and is never logged by the plugin.
58
+
59
+ ## Homebridge UI Configuration
60
+
61
+ The plugin ships a `config.schema.json`, so Homebridge UI can render the configuration form without a custom UI.
62
+
63
+ Sections:
64
+
65
+ - General settings: debug logging, queue size, duplicate behavior, global delay, optional test switch.
66
+ - LaMetric devices: internal ID, display name, host, protocol, port, API key, timeout, retries.
67
+ - Messages: internal ID, name, target devices, HomeKit switch exposure, auto-reset, cooldown, priority, icon type, cycles, frames, optional sound.
68
+
69
+ The schema can mask the API key with `format: password`. Per-device connection test buttons are not included in this version because the standard schema form does not provide a reliable server-side button flow by itself.
70
+
71
+ ## Example Configuration
72
+
73
+ ```json
74
+ {
75
+ "platform": "LaMetricTime",
76
+ "name": "LaMetric Time",
77
+ "debug": false,
78
+ "maxQueueSize": 50,
79
+ "duplicateStrategy": "drop",
80
+ "globalDelayMs": 250,
81
+ "testSwitch": true,
82
+ "devices": [
83
+ {
84
+ "id": "salon",
85
+ "name": "LaMetric Salon",
86
+ "host": "192.168.1.50",
87
+ "protocol": "http",
88
+ "port": 8080,
89
+ "apiKey": "SECRET",
90
+ "timeoutMs": 5000,
91
+ "retryCount": 2,
92
+ "retryBackoffMs": 500
93
+ }
94
+ ],
95
+ "messages": [
96
+ {
97
+ "id": "front-door-open",
98
+ "name": "Porte ouverte",
99
+ "deviceIds": ["salon"],
100
+ "exposeSwitch": true,
101
+ "autoResetMs": 1000,
102
+ "cooldownMs": 5000,
103
+ "priority": "info",
104
+ "iconType": "none",
105
+ "cycles": 1,
106
+ "frames": [
107
+ {
108
+ "order": 0,
109
+ "icon": "a1234",
110
+ "text": "Porte {{name}} ouverte"
111
+ }
112
+ ],
113
+ "sound": {
114
+ "enabled": true,
115
+ "category": "notifications",
116
+ "id": "positive1",
117
+ "repeat": 1
118
+ }
119
+ }
120
+ ]
121
+ }
122
+ ```
123
+
124
+ ## Home App Automation Example
125
+
126
+ 1. A HomeKit contact sensor detects that a front door opened.
127
+ 2. An Apple Home automation turns on the virtual switch `Porte ouverte`.
128
+ 3. Homebridge builds and queues the configured LaMetric notification.
129
+ 4. The plugin sends the notification locally to the selected LaMetric.
130
+ 5. The switch automatically returns to off after `autoResetMs`.
131
+
132
+ The plugin does not claim to observe every accessory managed by other Homebridge plugins directly. Use Apple Home automations or another supported trigger to turn on the virtual switch.
133
+
134
+ ## Notifications
135
+
136
+ Each message contains one or more frames. Frames are sorted by `order` during configuration validation.
137
+
138
+ Supported template variables:
139
+
140
+ - `{{date}}`
141
+ - `{{time}}`
142
+ - `{{name}}`
143
+ - `{{value}}`
144
+
145
+ Missing values render as an empty string. Templates do not execute JavaScript and do not use `eval` or `Function`.
146
+
147
+ ## Priorities, Icons, And Sounds
148
+
149
+ The LaMetric Device API documents notification priorities:
150
+
151
+ - `info`: normal queue priority.
152
+ - `warning`: higher priority than internal notifications.
153
+ - `critical`: interrupts other notifications and wakes the device from sleep/screensaver.
154
+
155
+ `iconType` supports `none`, `info`, and `alert`.
156
+
157
+ Frame icons can use LaMetric icon IDs such as:
158
+
159
+ - `i1234` for a static icon.
160
+ - `a1234` for an animated icon.
161
+
162
+ Sound categories supported by the API are `notifications` and `alarms`. The plugin omits the `sound` object entirely when sound is disabled.
163
+
164
+ ## Queue And Anti-Spam
165
+
166
+ The plugin keeps in-memory queues per LaMetric device:
167
+
168
+ - processing is sequential per device;
169
+ - different devices can process independently;
170
+ - queue size is limited;
171
+ - cooldown is applied per message after a successful send only;
172
+ - duplicates can be enqueued, dropped, or replaced;
173
+ - failures are logged and the queue continues.
174
+
175
+ Queues are not persisted. API keys and notification payloads are not written to log files by the plugin.
176
+
177
+ ## Troubleshooting
178
+
179
+ `401 Authentication refused`: verify the local API key and ensure there are no extra spaces.
180
+
181
+ `404 endpoint not found`: verify the host, port, protocol, and that the device supports Device API v2 notifications.
182
+
183
+ Timeout or unreachable device: verify that Homebridge can reach the LaMetric on the local network. HTTP usually uses port `8080`; HTTPS usually uses port `4343`.
184
+
185
+ `429 rate limit`: increase `globalDelayMs`, reduce automations that trigger the same message, or use cooldowns.
186
+
187
+ ## Security
188
+
189
+ - No cloud service is used.
190
+ - No telemetry is included.
191
+ - The plugin accepts host, protocol, and port, not arbitrary URLs.
192
+ - Only `http` and `https` protocols are accepted.
193
+ - Header injection characters are rejected.
194
+ - Text and payload inputs are bounded.
195
+ - API keys and Authorization headers are never logged.
196
+ - TLS validation is not disabled globally.
197
+
198
+ ## Development
199
+
200
+ ```sh
201
+ npm install
202
+ npm run lint
203
+ npm run build
204
+ npm test
205
+ npm run verify:pack
206
+ ```
207
+
208
+ Tests mock the LaMetric API and do not require a real device.
209
+
210
+ ## Publishing
211
+
212
+ Before publishing:
213
+
214
+ 1. Confirm repository, bugs, homepage, author, and license metadata.
215
+ 2. Run `npm run lint`, `npm run build`, `npm test`, and `npm run verify:pack`.
216
+ 3. Log in with `npm login`.
217
+ 4. Publish the alpha release with `npm publish --tag alpha`.
218
+
219
+ For a scoped package, use `npm publish --access=public` the first time.
@@ -0,0 +1,295 @@
1
+ {
2
+ "pluginAlias": "LaMetricTime",
3
+ "pluginType": "platform",
4
+ "singular": true,
5
+ "strictValidation": true,
6
+ "schema": {
7
+ "type": "object",
8
+ "required": ["platform", "name", "devices", "messages"],
9
+ "additionalProperties": false,
10
+ "properties": {
11
+ "platform": {
12
+ "type": "string",
13
+ "default": "LaMetricTime"
14
+ },
15
+ "name": {
16
+ "title": "Platform Name",
17
+ "type": "string",
18
+ "default": "LaMetric Time",
19
+ "description": "Name shown by Homebridge for this platform instance."
20
+ },
21
+ "debug": {
22
+ "title": "Debug Logging",
23
+ "type": "boolean",
24
+ "default": false
25
+ },
26
+ "queueStrategy": {
27
+ "title": "Queue Strategy",
28
+ "type": "string",
29
+ "default": "sequential",
30
+ "oneOf": [{ "title": "Sequential per device", "enum": ["sequential"] }]
31
+ },
32
+ "maxQueueSize": {
33
+ "title": "Maximum Queue Size",
34
+ "type": "integer",
35
+ "default": 50,
36
+ "minimum": 1,
37
+ "maximum": 500
38
+ },
39
+ "duplicateStrategy": {
40
+ "title": "Duplicate Notification Behavior",
41
+ "type": "string",
42
+ "default": "drop",
43
+ "oneOf": [
44
+ { "title": "Add duplicate notifications", "enum": ["enqueue"] },
45
+ { "title": "Drop duplicate notifications already queued", "enum": ["drop"] },
46
+ { "title": "Replace queued duplicate notifications", "enum": ["replace"] }
47
+ ]
48
+ },
49
+ "globalDelayMs": {
50
+ "title": "Global Delay Between Calls",
51
+ "type": "integer",
52
+ "default": 250,
53
+ "minimum": 0,
54
+ "maximum": 60000,
55
+ "description": "Minimum delay in milliseconds between two API calls to the same LaMetric."
56
+ },
57
+ "testSwitch": {
58
+ "title": "Expose Global Test Switch",
59
+ "type": "boolean",
60
+ "default": false
61
+ },
62
+ "devices": {
63
+ "title": "LaMetric Devices",
64
+ "type": "array",
65
+ "minItems": 1,
66
+ "items": {
67
+ "type": "object",
68
+ "required": ["id", "name", "host", "apiKey"],
69
+ "additionalProperties": false,
70
+ "properties": {
71
+ "id": {
72
+ "title": "Internal ID",
73
+ "type": "string",
74
+ "pattern": "^[a-zA-Z0-9][a-zA-Z0-9_-]{0,63}$",
75
+ "description": "Stable internal identifier used by messages. Do not change it after HomeKit accessories are created."
76
+ },
77
+ "name": {
78
+ "title": "Name",
79
+ "type": "string"
80
+ },
81
+ "host": {
82
+ "title": "Host",
83
+ "type": "string",
84
+ "description": "IP address or DNS name only. Do not enter a full URL."
85
+ },
86
+ "protocol": {
87
+ "title": "Protocol",
88
+ "type": "string",
89
+ "default": "http",
90
+ "oneOf": [
91
+ { "title": "HTTP local API, port 8080", "enum": ["http"] },
92
+ { "title": "HTTPS local API, port 4343", "enum": ["https"] }
93
+ ]
94
+ },
95
+ "port": {
96
+ "title": "Port",
97
+ "type": "integer",
98
+ "default": 8080,
99
+ "minimum": 1,
100
+ "maximum": 65535
101
+ },
102
+ "apiKey": {
103
+ "title": "Local API Key",
104
+ "type": "string",
105
+ "format": "password",
106
+ "description": "LaMetric local API key. It is sent only to the configured local device using HTTP Basic auth user dev."
107
+ },
108
+ "timeoutMs": {
109
+ "title": "HTTP Timeout",
110
+ "type": "integer",
111
+ "default": 5000,
112
+ "minimum": 250,
113
+ "maximum": 60000
114
+ },
115
+ "retryCount": {
116
+ "title": "Retry Count",
117
+ "type": "integer",
118
+ "default": 2,
119
+ "minimum": 0,
120
+ "maximum": 5
121
+ },
122
+ "retryBackoffMs": {
123
+ "title": "Retry Backoff",
124
+ "type": "integer",
125
+ "default": 500,
126
+ "minimum": 0,
127
+ "maximum": 30000
128
+ }
129
+ }
130
+ }
131
+ },
132
+ "messages": {
133
+ "title": "Messages",
134
+ "type": "array",
135
+ "items": {
136
+ "type": "object",
137
+ "required": ["id", "name", "deviceIds", "frames"],
138
+ "additionalProperties": false,
139
+ "properties": {
140
+ "id": {
141
+ "title": "Internal ID",
142
+ "type": "string",
143
+ "pattern": "^[a-zA-Z0-9][a-zA-Z0-9_-]{0,63}$",
144
+ "description": "Stable identifier used to generate the HomeKit accessory UUID."
145
+ },
146
+ "name": {
147
+ "title": "Name",
148
+ "type": "string"
149
+ },
150
+ "deviceIds": {
151
+ "title": "Target Device IDs",
152
+ "type": "array",
153
+ "minItems": 1,
154
+ "items": {
155
+ "type": "string"
156
+ },
157
+ "description": "IDs of LaMetric devices configured above."
158
+ },
159
+ "exposeSwitch": {
160
+ "title": "Expose HomeKit Switch",
161
+ "type": "boolean",
162
+ "default": true
163
+ },
164
+ "autoResetMs": {
165
+ "title": "Auto Reset Delay",
166
+ "type": "integer",
167
+ "default": 1000,
168
+ "minimum": 100,
169
+ "maximum": 60000
170
+ },
171
+ "cooldownMs": {
172
+ "title": "Cooldown",
173
+ "type": "integer",
174
+ "default": 5000,
175
+ "minimum": 0,
176
+ "maximum": 86400000
177
+ },
178
+ "priority": {
179
+ "title": "Priority",
180
+ "type": "string",
181
+ "default": "info",
182
+ "oneOf": [
183
+ { "title": "Info", "enum": ["info"] },
184
+ { "title": "Warning", "enum": ["warning"] },
185
+ { "title": "Critical", "enum": ["critical"] }
186
+ ]
187
+ },
188
+ "iconType": {
189
+ "title": "Notification Icon Type",
190
+ "type": "string",
191
+ "default": "none",
192
+ "oneOf": [
193
+ { "title": "None", "enum": ["none"] },
194
+ { "title": "Info", "enum": ["info"] },
195
+ { "title": "Alert", "enum": ["alert"] }
196
+ ]
197
+ },
198
+ "cycles": {
199
+ "title": "Display Cycles",
200
+ "type": "integer",
201
+ "default": 1,
202
+ "minimum": 1,
203
+ "maximum": 100
204
+ },
205
+ "value": {
206
+ "title": "Default Template Value",
207
+ "type": "string"
208
+ },
209
+ "frames": {
210
+ "title": "Frames",
211
+ "type": "array",
212
+ "minItems": 1,
213
+ "items": {
214
+ "type": "object",
215
+ "required": ["text"],
216
+ "additionalProperties": false,
217
+ "properties": {
218
+ "text": {
219
+ "title": "Text",
220
+ "type": "string",
221
+ "description": "Supports {{date}}, {{time}}, {{name}}, and {{value}}."
222
+ },
223
+ "icon": {
224
+ "title": "Icon ID",
225
+ "type": "string",
226
+ "description": "LaMetric icon ID such as i1234 for static icons or a1234 for animated icons."
227
+ },
228
+ "order": {
229
+ "title": "Order",
230
+ "type": "integer",
231
+ "default": 0,
232
+ "minimum": 0,
233
+ "maximum": 999
234
+ }
235
+ }
236
+ }
237
+ },
238
+ "sound": {
239
+ "title": "Sound",
240
+ "type": "object",
241
+ "additionalProperties": false,
242
+ "properties": {
243
+ "enabled": {
244
+ "title": "Enable Sound",
245
+ "type": "boolean",
246
+ "default": false
247
+ },
248
+ "category": {
249
+ "title": "Category",
250
+ "type": "string",
251
+ "default": "notifications",
252
+ "condition": { "functionBody": "return model.sound && model.sound.enabled === true;" },
253
+ "oneOf": [
254
+ { "title": "Notifications", "enum": ["notifications"] },
255
+ { "title": "Alarms", "enum": ["alarms"] }
256
+ ]
257
+ },
258
+ "id": {
259
+ "title": "Sound ID",
260
+ "type": "string",
261
+ "condition": { "functionBody": "return model.sound && model.sound.enabled === true;" }
262
+ },
263
+ "repeat": {
264
+ "title": "Repeat",
265
+ "type": "integer",
266
+ "default": 1,
267
+ "minimum": 0,
268
+ "maximum": 20,
269
+ "condition": { "functionBody": "return model.sound && model.sound.enabled === true;" }
270
+ }
271
+ }
272
+ }
273
+ }
274
+ }
275
+ }
276
+ }
277
+ },
278
+ "layout": [
279
+ {
280
+ "type": "section",
281
+ "title": "General Settings",
282
+ "items": ["name", "debug", "queueStrategy", "maxQueueSize", "duplicateStrategy", "globalDelayMs", "testSwitch"]
283
+ },
284
+ {
285
+ "type": "section",
286
+ "title": "LaMetric Devices",
287
+ "items": ["devices"]
288
+ },
289
+ {
290
+ "type": "section",
291
+ "title": "Messages",
292
+ "items": ["messages"]
293
+ }
294
+ ]
295
+ }
@@ -0,0 +1,7 @@
1
+ import type { PlatformAccessory } from 'homebridge';
2
+ import type { NormalizedMessageConfig } from '../config/types.js';
3
+ import type { LaMetricTimePlatform } from '../platform.js';
4
+ import { NotificationSwitchAccessory } from './notification-switch.js';
5
+ export declare class MessageAccessory extends NotificationSwitchAccessory {
6
+ constructor(platform: LaMetricTimePlatform, accessory: PlatformAccessory, message: NormalizedMessageConfig | undefined, testSwitch: boolean);
7
+ }
@@ -0,0 +1,7 @@
1
+ import { NotificationSwitchAccessory } from './notification-switch.js';
2
+ export class MessageAccessory extends NotificationSwitchAccessory {
3
+ constructor(platform, accessory, message, testSwitch) {
4
+ super(platform, accessory, message, testSwitch);
5
+ }
6
+ }
7
+ //# sourceMappingURL=message-accessory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"message-accessory.js","sourceRoot":"","sources":["../../src/accessories/message-accessory.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,2BAA2B,EAAE,MAAM,0BAA0B,CAAC;AAEvE,MAAM,OAAO,gBAAiB,SAAQ,2BAA2B;IAC/D,YACE,QAA8B,EAC9B,SAA4B,EAC5B,OAA4C,EAC5C,UAAmB;QAEnB,KAAK,CAAC,QAAQ,EAAE,SAAS,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;IAClD,CAAC;CACF"}
@@ -0,0 +1,13 @@
1
+ import type { PlatformAccessory } from 'homebridge';
2
+ import type { NormalizedMessageConfig } from '../config/types.js';
3
+ import type { LaMetricTimePlatform } from '../platform.js';
4
+ export declare class NotificationSwitchAccessory {
5
+ private readonly platform;
6
+ private readonly accessory;
7
+ private readonly message;
8
+ private readonly testSwitch;
9
+ private readonly service;
10
+ private resetTimer;
11
+ constructor(platform: LaMetricTimePlatform, accessory: PlatformAccessory, message: NormalizedMessageConfig | undefined, testSwitch: boolean);
12
+ private scheduleAutoReset;
13
+ }
@@ -0,0 +1,43 @@
1
+ export class NotificationSwitchAccessory {
2
+ platform;
3
+ accessory;
4
+ message;
5
+ testSwitch;
6
+ service;
7
+ resetTimer;
8
+ constructor(platform, accessory, message, testSwitch) {
9
+ this.platform = platform;
10
+ this.accessory = accessory;
11
+ this.message = message;
12
+ this.testSwitch = testSwitch;
13
+ const { Service: HapService, Characteristic } = this.platform.api.hap;
14
+ this.service = this.accessory.getService(HapService.Switch) ?? this.accessory.addService(HapService.Switch);
15
+ this.service.setCharacteristic(Characteristic.Name, this.accessory.displayName);
16
+ this.service
17
+ .getCharacteristic(Characteristic.On)
18
+ .onGet(() => false)
19
+ .onSet(async (value) => {
20
+ if (value !== true) {
21
+ return;
22
+ }
23
+ if (this.testSwitch) {
24
+ await this.platform.dispatchTestNotification();
25
+ }
26
+ else if (this.message) {
27
+ await this.platform.dispatchMessage(this.message);
28
+ }
29
+ this.scheduleAutoReset();
30
+ });
31
+ }
32
+ scheduleAutoReset() {
33
+ if (this.resetTimer) {
34
+ clearTimeout(this.resetTimer);
35
+ }
36
+ const delay = this.message?.autoResetMs ?? 1000;
37
+ this.resetTimer = setTimeout(() => {
38
+ this.service.updateCharacteristic(this.platform.api.hap.Characteristic.On, false);
39
+ this.resetTimer = undefined;
40
+ }, delay);
41
+ }
42
+ }
43
+ //# sourceMappingURL=notification-switch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notification-switch.js","sourceRoot":"","sources":["../../src/accessories/notification-switch.ts"],"names":[],"mappings":"AAIA,MAAM,OAAO,2BAA2B;IAKnB;IACA;IACA;IACA;IAPF,OAAO,CAAU;IAC1B,UAAU,CAA6B;IAE/C,YACmB,QAA8B,EAC9B,SAA4B,EAC5B,OAA4C,EAC5C,UAAmB;QAHnB,aAAQ,GAAR,QAAQ,CAAsB;QAC9B,cAAS,GAAT,SAAS,CAAmB;QAC5B,YAAO,GAAP,OAAO,CAAqC;QAC5C,eAAU,GAAV,UAAU,CAAS;QAEpC,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC;QACtE,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;QAC5G,IAAI,CAAC,OAAO,CAAC,iBAAiB,CAAC,cAAc,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;QAChF,IAAI,CAAC,OAAO;aACT,iBAAiB,CAAC,cAAc,CAAC,EAAE,CAAC;aACpC,KAAK,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC;aAClB,KAAK,CAAC,KAAK,EAAE,KAA0B,EAAE,EAAE;YAC1C,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;gBACnB,OAAO;YACT,CAAC;YACD,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;gBACpB,MAAM,IAAI,CAAC,QAAQ,CAAC,wBAAwB,EAAE,CAAC;YACjD,CAAC;iBAAM,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;gBACxB,MAAM,IAAI,CAAC,QAAQ,CAAC,eAAe,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YACpD,CAAC;YACD,IAAI,CAAC,iBAAiB,EAAE,CAAC;QAC3B,CAAC,CAAC,CAAC;IACP,CAAC;IAEO,iBAAiB;QACvB,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YACpB,YAAY,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAChC,CAAC;QACD,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,EAAE,WAAW,IAAI,IAAI,CAAC;QAChD,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC,GAAG,EAAE;YAChC,IAAI,CAAC,OAAO,CAAC,oBAAoB,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,cAAc,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;YAClF,IAAI,CAAC,UAAU,GAAG,SAAS,CAAC;QAC9B,CAAC,EAAE,KAAK,CAAC,CAAC;IACZ,CAAC;CACF"}
@@ -0,0 +1,28 @@
1
+ import type { NormalizedPlatformConfig } from './types.js';
2
+ export declare const DEFAULT_PORT_BY_PROTOCOL: {
3
+ readonly http: 8080;
4
+ readonly https: 4343;
5
+ };
6
+ export declare const DEFAULTS: {
7
+ platformName: string;
8
+ debug: false;
9
+ queueStrategy: string;
10
+ maxQueueSize: number;
11
+ duplicateStrategy: string;
12
+ globalDelayMs: number;
13
+ testSwitch: false;
14
+ protocol: string;
15
+ timeoutMs: number;
16
+ retryCount: number;
17
+ retryBackoffMs: number;
18
+ autoResetMs: number;
19
+ cooldownMs: number;
20
+ priority: string;
21
+ iconType: string;
22
+ cycles: number;
23
+ soundCategory: string;
24
+ soundRepeat: number;
25
+ frameOrder: number;
26
+ value: string;
27
+ };
28
+ export declare const EMPTY_CONFIG: NormalizedPlatformConfig;
@@ -0,0 +1,40 @@
1
+ import { DEFAULT_PLATFORM_NAME } from '../settings.js';
2
+ export const DEFAULT_PORT_BY_PROTOCOL = {
3
+ http: 8080,
4
+ https: 4343,
5
+ };
6
+ export const DEFAULTS = {
7
+ platformName: DEFAULT_PLATFORM_NAME,
8
+ debug: false,
9
+ queueStrategy: 'sequential',
10
+ maxQueueSize: 50,
11
+ duplicateStrategy: 'drop',
12
+ globalDelayMs: 250,
13
+ testSwitch: false,
14
+ protocol: 'http',
15
+ timeoutMs: 5000,
16
+ retryCount: 2,
17
+ retryBackoffMs: 500,
18
+ autoResetMs: 1000,
19
+ cooldownMs: 0,
20
+ priority: 'info',
21
+ iconType: 'none',
22
+ cycles: 1,
23
+ soundCategory: 'notifications',
24
+ soundRepeat: 1,
25
+ frameOrder: 0,
26
+ value: '',
27
+ };
28
+ export const EMPTY_CONFIG = {
29
+ platform: 'LaMetricTime',
30
+ name: DEFAULTS.platformName,
31
+ debug: DEFAULTS.debug,
32
+ queueStrategy: 'sequential',
33
+ maxQueueSize: DEFAULTS.maxQueueSize,
34
+ duplicateStrategy: 'drop',
35
+ globalDelayMs: DEFAULTS.globalDelayMs,
36
+ testSwitch: DEFAULTS.testSwitch,
37
+ devices: [],
38
+ messages: [],
39
+ };
40
+ //# sourceMappingURL=defaults.js.map